当前位置: 移动技术网 > IT编程>开发语言>Java > spring-security实现的token授权

spring-security实现的token授权

2019年03月16日  | 移动技术网IT编程  | 我要评论

l216,蔡慧亭,svchost占用内存过高

在我的用户密码授权文章里介绍了spring-security的工作过程,不了解的同学,可以先看看这篇文章,在
用户密码授权模式里,主要是通过一个登陆页进行授权,然后把授权对象写到session里,它主要用在mvc框架里,而对于webapi来说,一般不会采用这种方式,对于webapi
来说,一般会用jwt授权方式,就是token授权码的方式,每访问api接口时,在http头上带着你的token码,而大叔自己也写了一个简单的jwt授权模式,下面介绍一下。

websecurityconfig授权配置

@configuration
@enablewebsecurity
@enableglobalmethodsecurity(prepostenabled = true)
public class tokenwebsecurityconfig extends websecurityconfigureradapter {
  /**
   * token过滤器.
   */
  @autowired
  lindtokenauthenticationfilter lindtokenauthenticationfilter;

  @bean
  @override
  public authenticationmanager authenticationmanagerbean() throws exception {
    return super.authenticationmanagerbean();
  }

  @override
  protected void configure(httpsecurity httpsecurity) throws exception {
    httpsecurity
        .csrf().disable()
        // 基于token,所以不需要session
        .sessionmanagement().sessioncreationpolicy(sessioncreationpolicy.stateless).and()
        .authorizerequests()
        // 对于获取token的rest api要允许匿名访问
        .antmatchers("/lind-auth/**").permitall()
        // 除上面外的所有请求全部需要鉴权认证
        .anyrequest().authenticated();
    httpsecurity
        .addfilterbefore(lindtokenauthenticationfilter, usernamepasswordauthenticationfilter.class);
    // 禁用缓存
    httpsecurity.headers().cachecontrol();
  }

  /**
   * 密码生成策略.
   *
   * @return
   */
  @bean
  public passwordencoder passwordencoder() {
    return new bcryptpasswordencoder();
  }
}

授权接口login

对外开放的,需要提供用户名和密码为参数进行登陆,然后返回token码,当然也可以使用手机号和验证码登陆,授权逻辑是一样的,获取用户信息都是使用userdetailsservice,
然后开发人员根据自己的业务去重写loaduserbyusername来获取用户实体。

用户登陆成功后,为它授权及认证,这一步我们会在redis里建立token与用户名的关系。

@getmapping(login)
  public responseentity<?> refreshandgetauthenticationtoken(
      @requestparam string username,
      @requestparam string password) throws authenticationexception {
    return responseentity.ok(generatetoken(username, password));
  }

  /**
   * 登陆与授权.
   *
   * @param username .
   * @param password .
   * @return
   */
  private string generatetoken(string username, string password) {
    usernamepasswordauthenticationtoken uptoken = new usernamepasswordauthenticationtoken(username, password);
    // perform the security
    final authentication authentication = authenticationmanager.authenticate(uptoken);
    securitycontextholder.getcontext().setauthentication(authentication);
    // reload password post-security so we can generate token
    final userdetails userdetails = userdetailsservice.loaduserbyusername(username);
    // 持久化的redis
    string token = commonutils.encrypt(userdetails.getusername());
    redistemplate.opsforvalue().set(token, userdetails.getusername());
    return token;
  }

lindtokenauthenticationfilter代码

主要实现了对请求的拦截,获取http头上的authorization元素,token码就在这个键里,我们的token都是采用通用的bearer开头,当你的token没有过期时,会
存储在redis里,key就是用户名的md5码,而value就是用户名,当拿到token之后去数据库或者缓存里拿用户信息进行授权即可。

/**
 * token filter bean.
 */
@component
public class lindtokenauthenticationfilter extends onceperrequestfilter {

  @autowired
  redistemplate<string, string> redistemplate;
  string tokenhead = "bearer ";
  string tokenheader = "authorization";
  @autowired
  private userdetailsservice userdetailsservice;

  /**
   * token filter.
   *
   * @param request     .
   * @param response    .
   * @param filterchain .
   */
  @override
  protected void dofilterinternal(
      httpservletrequest request,
      httpservletresponse response,
      filterchain filterchain) throws servletexception, ioexception {

    string authheader = request.getheader(this.tokenheader);
    if (authheader != null && authheader.startswith(tokenhead)) {
      final string authtoken = authheader.substring(tokenhead.length()); // the part after "bearer "
      if (authtoken != null && redistemplate.haskey(authtoken)) {
        string username = redistemplate.opsforvalue().get(authtoken);
        if (username != null && securitycontextholder.getcontext().getauthentication() == null) {
          userdetails userdetails = this.userdetailsservice.loaduserbyusername(username);
          //可以校验token和username是否有效,目前由于token对应username存在redis,都以默认都是有效的
          usernamepasswordauthenticationtoken authentication = new usernamepasswordauthenticationtoken(
              userdetails, null, userdetails.getauthorities());
          authentication.setdetails(new webauthenticationdetailssource().builddetails(
              request));
          logger.info("authenticated user " + username + ", setting security context");
          securitycontextholder.getcontext().setauthentication(authentication);
        }
      }
    }

    filterchain.dofilter(request, response);

  }

测试token授权

get:http://localhost:8080/lind-demo/login?username=admin&password=123

post:http://localhost:8080/lind-demo/user/add
content-type:application/json
authorization:bearer 21232f297a57a5a743894a0e4a801fc3

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网