Sprint Boot使用OAuth和JWT实现身份认证【一】

举报
清雨小竹 发表于 2022/09/25 02:00:19 2022/09/25
1.3k+ 0 0
【摘要】 依赖第三方库: compile 'io.jsonwebtoken:jjwt:0.9.0' 1.先写个例子用JWT实现获取token和解析token package com.yf.gyy.OAuthController; import java.util.Date;import java.util.HashMap;import java...

依赖第三方库

compile 'io.jsonwebtoken:jjwt:0.9.0'
 

1.先写个例子用JWT实现获取token和解析token


      package com.yf.gyy.OAuthController;
      import java.util.Date;
      import java.util.HashMap;
      import java.util.Map;
      import org.springframework.web.bind.annotation.RequestBody;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      import io.jsonwebtoken.Claims;
      import io.jsonwebtoken.Jwts;
      import io.jsonwebtoken.SignatureAlgorithm;
      import io.swagger.annotations.Api;
      import io.swagger.annotations.ApiOperation;
      @RestController
      @Api(value="OAuth2测试")
      public class OAuthController {
     	@ApiOperation(value="测试获取token",httpMethod="POST")
     	@RequestMapping("/api/testOAuth/GetToken")
     	public String CreateToken()
      	{
      		Map<String, Object> claims=new HashMap<String, Object>();
      		claims.put("zzzili", "zz");
     		String token = Jwts.builder()
      	            .setClaims(claims)
      	            .setExpiration(new Date(System.currentTimeMillis() + 6000 * 1000))
      	            .signWith(SignatureAlgorithm.HS512,"thisiskey") //采用什么算法是可以自己选择的,不一定非要采用HS512
      	            .compact();
     		return token;
      	}
     	@ApiOperation(value="测试token解析",httpMethod="POST")
     	@RequestMapping("/api/testOAuth/TestOAuth2")
     	public Claims TestOAuth2( @RequestBody String token)
      	{
      		System.out.println(token);
     		Claims  claims = Jwts.parser()
                      .setSigningKey("thisiskey")
                      .parseClaimsJws(token)
                      .getBody();
     		return claims;
      	}
      }
  
 

2.对spring boot项目添加OAuth过滤器

我们暂且实现,自己定义获取token的方法和自定义过滤器

需要4个java类

>>http请求过滤器类,继承自 OncePerRequestFilter

>>过滤器注册类,继承自 WebSecurityConfigurerAdapter

>>用户对象类,继承自 UserDetails

>>用户对象加密解密类

2.1添加一个rest方法,用以获取token:


     	@ApiOperation(value="测试获取token",httpMethod="POST")
     	@RequestMapping("/api/testOAuth2/GetToken")
     	public String CreateToken()
      	{
      		List<String> roles = new ArrayList<String>();
          	roles.add("USER");
          	roles.add("ADMIN");
          	Map<String, Object> u=new HashMap<String, Object>();
          	u.put("password", "zzz");
          	u.put("username", "zzz");
          	u.put("created", "zzz");
         	String token = Jwts.builder()
      	            .setClaims(u)
      	            .setExpiration(new Date(System.currentTimeMillis() + 6000 * 1000))
      	            .signWith(SignatureAlgorithm.HS512,"123456") //采用什么算法是可以自己选择的,不一定非要采用HS512
      	            .compact();
     		return token;
      	}
  
 

2.2自定义http请求过滤器


      package com.yf.gyy;
      import java.io.IOException;
      import java.util.ArrayList;
      import java.util.Calendar;
      import java.util.Date;
      import java.util.List;
      import javax.servlet.FilterChain;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
      import org.springframework.security.core.context.SecurityContextHolder;
      import org.springframework.security.core.userdetails.UserDetails;
      import org.springframework.security.core.userdetails.UsernameNotFoundException;
      import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
      import org.springframework.stereotype.Component;
      import org.springframework.web.filter.OncePerRequestFilter;
      import io.jsonwebtoken.Claims;
      import io.jsonwebtoken.Jwts;
      @Component
      public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
         @Autowired
         private JwtTokenUtil jwtTokenUtil;
         @Override
         protected void doFilterInternal(
       HttpServletRequest request,
       HttpServletResponse response,
       FilterChain chain) throws ServletException, IOException {
         	String tokenHeader = "Authorization";
         	String tokenHead = "Bearer ";
             String authHeader = request.getHeader(tokenHeader);
             if (authHeader != null && authHeader.startsWith(tokenHead)) {
                 final String authToken = authHeader.substring(tokenHead.length());
                 Claims  claims = Jwts.parser()
                          .setSigningKey("123456")
                          .parseClaimsJws(authToken)
                          .getBody();
                 String username = claims.get("username").toString();
                 if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                 	UserDetails userDetails = loadUserByUsername(username);
                     if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                         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);
                      }
                  }
              }
              chain.doFilter(request, response);
          }
         private UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
          	List<String> roles = new ArrayList<String>();
          	roles.add("USER");
          	roles.add("ADMIN");
         	Calendar c = Calendar.getInstance();
              c.setTime(new Date());
              c.add(Calendar.DAY_OF_MONTH, 10);// 今天+10天
              Date nowT= c.getTime();
         	JwtUser user = new JwtUser("zzz",
         			"zzz",
         			"zzz",
         			"email",
          			roles,
          			nowT);
         	return user;
          }
      }
  
 

      package com.yf.gyy;
      import java.io.Serializable;
      import java.util.Date;
      import java.util.Map;
      import org.springframework.security.core.userdetails.UserDetails;
      import org.springframework.stereotype.Component;
      import io.jsonwebtoken.Claims;
      import io.jsonwebtoken.Jwts;
      import io.jsonwebtoken.SignatureAlgorithm;
      /**
       * @author
       * JwtTokenUtil
       */
      //@Component("jwtTokenUtil")
      @Component
      public class JwtTokenUtil implements Serializable {
         private static final long serialVersionUID = -3301605591108950415L;
         static final String CLAIM_KEY_USERNAME = "username";
         static final String CLAIM_KEY_PASSWORD = "password";
         static final String CLAIM_KEY_CREATED = "created";
         //private static final String AUDIENCE_UNKNOWN = "unknown";
         //private static final String AUDIENCE_WEB = "web";
         //private static final String AUDIENCE_MOBILE = "mobile";
         //private static final String AUDIENCE_TABLET = "tablet";
         //通过@value注解获取密钥
         //@Value("123456")
         private String secret="123456";
         //通过@value注解获取失效时间
         //@Value("${jwt.expiration}")
         private Long expiration=300L;
         //@Resource(name = "tokenConfig")
         //private Map<String, String> tokenConfig;
         /**
       * @param token
       * return username by Token
       */
         public String getUsernameFromToken(String token) {
              String username;
             try {
                 final Claims claims = getClaimsFromToken(token);
                  username = (String) claims.get(CLAIM_KEY_USERNAME);
                 //username = claims.getSubject();
              } catch (Exception e) {
                  username = null;
              }
             return username;
          }
         /**
       * @param token
       * return CreatedDate by Token 获取token创建时间
       */
         public Date getCreatedDateFromToken(String token) {
              Date created;
             try {
                 final Claims claims = getClaimsFromToken(token);
                  created = new Date((Long) claims.get(CLAIM_KEY_CREATED));
              } catch (Exception e) {
                  created = null;
              }
             return created;
          }
         /**
       * @param token
       * return ExpirationDate by Token 获取token过期时间
       */
         public Date getExpirationDateFromToken(String token) {
              Date expiration;
             try {
                 final Claims claims = getClaimsFromToken(token);
                  expiration = claims.getExpiration();
              } catch (Exception e) {
                  expiration = null;
              }
             return expiration;
          }
         /**
       * @param token
       * return Password by Token 获取token的密码
       */
         public String getPasswordFromToken(String token) {
              String password;
             try {
                 final Claims claims = getClaimsFromToken(token);
                  password = (String) claims.get(CLAIM_KEY_PASSWORD);
              } catch (Exception e) {
                  password = null;
              }
             return password;
          }
         public Claims getClaimsFromToken(String token) {
              Claims claims;
             try {
                  claims = Jwts.parser()
                         //设置签名的密钥
                          .setSigningKey(secret)
                         //把token转换成断言
                          .parseClaimsJws(token)
                          .getBody();
                 //Date expirationTime = Jwts.parser().setSigningKey(secret).parseClaimsJwt(token).getBody().getExpiration();
              } catch (Exception e) {
                  claims = null;
              }
             return claims;
          }
         //生成到期日期
         private Date generateExpirationDate() {
             return new Date(System.currentTimeMillis() + expiration * 1000);
          }
         //判断token是否过期
         private Boolean isTokenExpired(String token) {
             final Date expiration = getExpirationDateFromToken(token);
             return expiration.before(new Date());
          }
         //判断token创建时间是否在密码重置之前
         private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
             return (lastPasswordReset != null && created.before(lastPasswordReset));
          }
         /*private String generateAudience(Device device) {
       String audience = AUDIENCE_UNKNOWN;
       if (device.isNormal()) {
       audience = AUDIENCE_WEB;
       } else if (device.isTablet()) {
       audience = AUDIENCE_TABLET;
       } else if (device.isMobile()) {
       audience = AUDIENCE_MOBILE;
       }
       return audience;
       }
       //忽略token的过期时间
       private Boolean ignoreTokenExpiration(String token) {
       String audience = getPasswordFromToken(token);
       return (AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience));
       }*/
         //生成token
         public String generateToken(Map<String, Object> claims) {
             return Jwts.builder()
                      .setClaims(claims)
                      .setExpiration(generateExpirationDate())
                      .signWith(SignatureAlgorithm.HS512, secret)
                      .compact();
          }
         //判断token是否可以刷新
         public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
             final Date created = getCreatedDateFromToken(token);
             return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
                      && (!isTokenExpired(token)) ;
                     /*|| ignoreTokenExpiration(token))*/
          }
         //刷新token
         public String refreshToken(String token) {
              String refreshedToken;
             try {
                 final Claims claims = getClaimsFromToken(token);
                  claims.put(CLAIM_KEY_CREATED, new Date());
                  refreshedToken = generateToken(claims);
              } catch (Exception e) {
                  refreshedToken = null;
              }
             return refreshedToken;
          }
         //判读token是否有效
         public Boolean validateToken(String token, UserDetails userDomain) {
            // JwtUser user = (JwtUser) userPO;
             final String username = getUsernameFromToken(token);
             //final Date created = getCreatedDateFromToken(token);
             //final Date expiration = getExpirationDateFromToken(token);
             if(username==null){
                 return false;
              }else{
             return (
                      username.equals(userDomain.getUsername())
                              && !isTokenExpired(token));
                             //&& !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate()));
          }
          }
         //public String getTokenKey() {
         // return tokenConfig.get("tokenKey");
         //}
      }
  
 


      package com.yf.gyy;
      import java.util.Collection;
      import java.util.Date;
      import java.util.List;
      import java.util.stream.Collectors;
      import org.springframework.security.core.GrantedAuthority;
      import org.springframework.security.core.authority.SimpleGrantedAuthority;
      import org.springframework.security.core.userdetails.UserDetails;
      import com.fasterxml.jackson.annotation.JsonIgnore;
      public class JwtUser implements UserDetails {
         /**
       *
       */
     	private static final long serialVersionUID = 1L;
     	private final String id;
         private final String username;
         private final String password;
         private final String email;
         private final Collection<? extends GrantedAuthority> authorities;
         private final Date lastPasswordResetDate;
         public JwtUser(
       String id,
       String username,
       String password,
       String email,
       List<String> authorities,
       Date lastPasswordResetDate) {
             this.id = id;
             this.username = username;
             this.password = password;
             this.email = email;
             this.authorities = mapToGrantedAuthorities(authorities);
             this.lastPasswordResetDate = lastPasswordResetDate;
          }
         private  List<GrantedAuthority> mapToGrantedAuthorities(List<String> authorities) {
             return authorities.stream()
                      .map(SimpleGrantedAuthority::new)
                      .collect(Collectors.toList());
          }
         //返回分配给用户的角色列表
         @Override
         public Collection<? extends GrantedAuthority> getAuthorities() {
             return authorities;
          }
         @JsonIgnore
         public String getId() {
             return id;
          }
         @JsonIgnore
         @Override
         public String getPassword() {
             return password;
          }
         @Override
         public String getUsername() {
             return username;
          }
         // 账户是否未过期
         @JsonIgnore
         @Override
         public boolean isAccountNonExpired() {
             return true;
          }
         // 账户是否未锁定
         @JsonIgnore
         @Override
         public boolean isAccountNonLocked() {
             return true;
          }
         // 密码是否未过期
         @JsonIgnore
         @Override
         public boolean isCredentialsNonExpired() {
             return true;
          }
         // 账户是否激活
         @JsonIgnore
         @Override
         public boolean isEnabled() {
             return true;
          }
         // 这个是自定义的,返回上次密码重置日期
         @JsonIgnore
         public Date getLastPasswordResetDate() {
             return lastPasswordResetDate;
          }
     	public String getEmail() {
     		return email;
      	}
      }
  
 

2.3将过滤器装在到webconfig中


      package com.yf.gyy;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.http.HttpMethod;
      import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
      import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
      import org.springframework.security.config.annotation.web.builders.HttpSecurity;
      import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
      import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
      import org.springframework.security.config.http.SessionCreationPolicy;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;
      import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
      @Configuration
      @EnableWebSecurity
      @EnableGlobalMethodSecurity(prePostEnabled = true)
      public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
         @Override
         protected void configure(HttpSecurity httpSecurity) throws Exception {
          	httpSecurity
          	.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
          	.csrf().disable()
          	.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
               .requestMatchers().anyRequest();
          }
         @Bean
         public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
             return new JwtAuthenticationTokenFilter();
          }
      }
  
 

3.在rest接口中使用标注添加访问权限:


      package com.yf.gyy.OAuthController;
      import org.springframework.security.access.prepost.PreAuthorize;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      import io.swagger.annotations.Api;
      import io.swagger.annotations.ApiOperation;
      @RestController
      @Api(value="OAuth2测试")
      //@PreAuthorize("hasRole('ROLE_USER')") //判断角色
      @PreAuthorize("principal.username!=null") //用户名不为空
      public class OAuthController {
     	@ApiOperation(value="测试访问授权",httpMethod="POST")
     	@RequestMapping("/api/testOAuth/TestAccessToken")
     	public String TestAccessToken()
      	{
     		return "test oauth";
      	}
      }
  
 

文章来源: zzzili.blog.csdn.net,作者:清雨小竹,版权归原作者所有,如需转载,请联系作者。

原文链接:zzzili.blog.csdn.net/article/details/79383919

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。