Sprint Boot使用OAuth和JWT实现身份认证【二】
【摘要】
上一篇文章已经实现了自定义获取token方法和自定义过滤器,本篇文章对自定义类进行封装:
文件结构:
依赖:
dependencies { compile('com.github.wenhao:jpa-spec:3.1.1') compile('io.springfox:springfox-swagger2:2.2....
上一篇文章已经实现了自定义获取token方法和自定义过滤器,本篇文章对自定义类进行封装:
文件结构:
依赖:
dependencies {
compile('com.github.wenhao:jpa-spec:3.1.1')
compile('io.springfox:springfox-swagger2:2.2.2')
compile('io.springfox:springfox-swagger-ui:2.2.2')
compile 'io.jsonwebtoken:jjwt:0.9.0'
compile 'com.alibaba:fastjson:1.2.44'
compile('org.springframework.security:spring-security-jwt')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.security.oauth:spring-security-oauth2')
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-jdbc')
compile('org.springframework.boot:spring-boot-starter-web')
runtime('mysql:mysql-connector-java')
providedRuntime('org.springframework.boot:spring-boot-starter-tomcat')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
package com.yf.gyy.OAuthConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.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 JWTAuthenticationFilter authenticationTokenFilterBean() throws Exception {
return new JWTAuthenticationFilter();
}
}
package com.yf.gyy.OAuthConfig;
import java.io.IOException;
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.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 JWTAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JWTUtils 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(JWTUtils.secret)
.parseClaimsJws(authToken)
.getBody();
UserDetails userDetails = jwtTokenUtil.getUserFromToken(claims);
if (jwtTokenUtil.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
}
package com.yf.gyy.OAuthConfig;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class JWTUserDetails implements UserDetails {
private String userId;
private String password;
private final String username;
private final Collection<? extends GrantedAuthority> authorities;
private final boolean accountNonExpired;
private final boolean accountNonLocked;
private final boolean credentialsNonExpired;
private final boolean enabled;
public JWTUserDetails(String userId, String username, String password, Collection<? extends GrantedAuthority> authorities) {
this(userId, username, password, true, true, true, true, authorities);
}
public JWTUserDetails(String userId, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
if (username != null && !"".equals(username) && password != null) {
this.userId = userId;
this.username = username;
this.password = password;
this.enabled = enabled;
this.accountNonExpired = accountNonExpired;
this.credentialsNonExpired = credentialsNonExpired;
this.accountNonLocked = accountNonLocked;
this.authorities = authorities;
} else {
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
}
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public String getUserId() {
return userId;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
package com.yf.gyy.OAuthConfig;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
@Component
public class JWTUtils {
public static final String ROLE_REFRESH_TOKEN = "ROLE_REFRESH_TOKEN";
private static final String CLAIM_KEY_USER_ID = "user_id";
private static final String CLAIM_KEY_AUTHORITIES = "scope";
private static final String CLAIM_KEY_ACCOUNT_ENABLED = "enabled";
private static final String CLAIM_KEY_ACCOUNT_NON_LOCKED = "non_locked";
private static final String CLAIM_KEY_ACCOUNT_NON_EXPIRED = "non_expired";
public static String secret = "123456";
private static Long access_token_expiration = 30000L;
private static Long refresh_token_expiration = 30000L;
/*@Value("${jwt.secret}")
private String secret;
@Value("${jwt.access_token.expiration}")
private Long access_token_expiration;
@Value("${jwt.refresh_token.expiration}")
private Long refresh_token_expiration;*/
private final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;
public JWTUserDetails getUserFromToken(String token) {
JWTUserDetails user;
try {
final Claims claims = getClaimsFromToken(token);
String userId = getUserIdFromToken(token);
String username = claims.getSubject();
List roles = (List) claims.get(CLAIM_KEY_AUTHORITIES);
Collection<? extends GrantedAuthority> authorities = parseArrayToAuthorities(roles);
boolean account_enabled = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_ENABLED);
boolean account_non_locked = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_NON_LOCKED);
boolean account_non_expired = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_NON_EXPIRED);
user = new JWTUserDetails(userId, username, "password", account_enabled, account_non_expired, true, account_non_locked, authorities);
} catch (Exception e) {
user = null;
}
return user;
}
public JWTUserDetails getUserFromToken(Claims claims) {
JWTUserDetails user;
try {
//final Claims claims = getClaimsFromToken(token);
String userId = claims.get(CLAIM_KEY_USER_ID).toString();//getUserIdFromToken(token);
String username = claims.get(CLAIM_KEY_USER_ID).toString();//claims.getSubject();
List roles = (List) claims.get(CLAIM_KEY_AUTHORITIES);
Collection<? extends GrantedAuthority> authorities = parseArrayToAuthorities(roles);
boolean account_enabled = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_ENABLED);
boolean account_non_locked = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_NON_LOCKED);
boolean account_non_expired = (Boolean) claims.get(CLAIM_KEY_ACCOUNT_NON_EXPIRED);
user = new JWTUserDetails(userId, username, "password", account_enabled, account_non_expired, true, account_non_locked, authorities);
} catch (Exception e) {
user = null;
}
return user;
}
public String getUserIdFromToken(String token) {
String userId;
try {
final Claims claims = getClaimsFromToken(token);
userId = claims.get(CLAIM_KEY_USER_ID).toString();
} catch (Exception e) {
userId = "";
}
return userId;
}
public String getUsernameFromToken(String token) {
String username;
try {
final Claims claims = getClaimsFromToken(token);
username = claims.get(CLAIM_KEY_USER_ID).toString();
} catch (Exception e) {
username = null;
}
return username;
}
public Date getCreatedDateFromToken(String token) {
Date created;
try {
final Claims claims = getClaimsFromToken(token);
created = claims.getIssuedAt();
} catch (Exception e) {
created = null;
}
return created;
}
public Date getExpirationDateFromToken(String token) {
Date expiration;
try {
final Claims claims = getClaimsFromToken(token);
expiration = claims.getExpiration();
} catch (Exception e) {
expiration = null;
}
return expiration;
}
private Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
private Date generateExpirationDate(long expiration) {
return new Date(System.currentTimeMillis() + expiration * 1000);
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
return (lastPasswordReset != null && created.before(lastPasswordReset));
}
public String generateAccessToken(UserDetails userDetails) {
JWTUserDetails user = (JWTUserDetails) userDetails;
Map<String, Object> claims = generateClaims(user);
claims.put(CLAIM_KEY_AUTHORITIES, JSON.toJSON(authoritiesToArray(user.getAuthorities())));
return generateAccessToken(user.getUsername(), claims);
}
public Map<String, Object> generateAccessTokenToMap(UserDetails userDetails) {
JWTUserDetails user = (JWTUserDetails) userDetails;
Map<String, Object> claims = generateClaims(user);
claims.put(CLAIM_KEY_AUTHORITIES, JSON.toJSON(authoritiesToArray(user.getAuthorities())));
return claims;
}
private Map<String, Object> generateClaims(JWTUserDetails user) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USER_ID, user.getUserId());
claims.put(CLAIM_KEY_ACCOUNT_ENABLED, user.isEnabled());
claims.put(CLAIM_KEY_ACCOUNT_NON_LOCKED, user.isAccountNonLocked());
claims.put(CLAIM_KEY_ACCOUNT_NON_EXPIRED, user.isAccountNonExpired());
return claims;
}
private String generateAccessToken(String subject, Map<String, Object> claims) {
return generateToken(subject, claims, access_token_expiration);
}
private List authoritiesToArray(Collection<? extends GrantedAuthority> authorities) {
List<String> list = new ArrayList<>();
for (GrantedAuthority ga : authorities) {
list.add(ga.getAuthority());
}
return list;
}
private Collection<? extends GrantedAuthority> parseArrayToAuthorities(List roles) {
Collection<GrantedAuthority> authorities = new ArrayList<>();
SimpleGrantedAuthority authority;
for (Object role : roles) {
authority = new SimpleGrantedAuthority(role.toString());
authorities.add(authority);
}
return authorities;
}
public String generateRefreshToken(UserDetails userDetails) {
JWTUserDetails user = (JWTUserDetails) userDetails;
Map<String, Object> claims = generateClaims(user);
// 只授于更新 token 的权限
String roles[] = new String[]{JWTUtils.ROLE_REFRESH_TOKEN};
claims.put(CLAIM_KEY_AUTHORITIES, JSON.toJSON(roles));
return generateRefreshToken(user.getUsername(), claims);
}
private String generateRefreshToken(String subject, Map<String, Object> claims) {
return generateToken(subject, claims, refresh_token_expiration);
}
public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
final Date created = getCreatedDateFromToken(token);
return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
&& (!isTokenExpired(token));
}
public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = getClaimsFromToken(token);
refreshedToken = generateAccessToken(claims.getSubject(), claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
private String generateToken(String subject, Map<String, Object> claims, long expiration) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setId(UUID.randomUUID().toString())
.setIssuedAt(new Date())
.setExpiration(generateExpirationDate(expiration))
.compressWith(CompressionCodecs.DEFLATE)
.signWith(SIGNATURE_ALGORITHM, secret)
.compact();
}
public Boolean validateToken(String token, UserDetails userDetails) {
JWTUserDetails user = (JWTUserDetails) userDetails;
final String userId = getUserIdFromToken(token);
final String username = getUsernameFromToken(token);
// final Date created = getCreatedDateFromToken(token);
// final Date expiration = getExpirationDateFromToken(token);
return (userId.equals(user.getUserId())
&& username.equals(user.getUsername())
&& !isTokenExpired(token)
/* && !isCreatedBeforeLastPasswordReset(created, userDetails.getLastPasswordResetDate()) */
);
}
}
package com.yf.gyy.OAuthController;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yf.gyy.OAuthConfig.JWTUserDetails;
import com.yf.gyy.OAuthConfig.JWTUtils;
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 OAuthController2 {
@ApiOperation(value="测试获取token",httpMethod="POST")
@RequestMapping("/api/testOAuth2/GetToken")
public String CreateToken()
{
List<String> roles = new ArrayList<String>();
roles.add("USER");
roles.add("ADMIN");
JWTUserDetails user = new JWTUserDetails("zzz",
"zzz",
"zzz",
mapToGrantedAuthorities(roles));
JWTUtils jwtUtils = new JWTUtils();
Map<String, Object> claims = jwtUtils.generateAccessTokenToMap(user);
String token = Jwts.builder()
.setClaims(claims)
.setExpiration(new Date(System.currentTimeMillis() + 6000 * 1000))
.signWith(SignatureAlgorithm.HS512,"123456") //采用什么算法是可以自己选择的,不一定非要采用HS512
.compact();
return token;
}
private List<GrantedAuthority> mapToGrantedAuthorities(List<String> authorities) {
return authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
@ApiOperation(value="测试token解析",httpMethod="POST")
@RequestMapping("/api/testOAuth2/TestOAuth2")
public Claims TestOAuth2( @RequestBody String token)
{
System.out.println(token);
Claims claims = Jwts.parser()
.setSigningKey("123456")
.parseClaimsJws(token)
.getBody();
return claims;
}
}
package com.yf.gyy.OAuthController;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yf.gyy.OAuthConfig.JWTUserDetails;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@RestController
@Api(value="OAuth2测试")
//@PreAuthorize("hasRole('ROLE_USER')") //判断角色
@PreAuthorize("authenticated")
//@PreAuthorize("principal.username!=null") //用户名不为空
public class OAuthController {
@ApiOperation(value="测试访问授权",httpMethod="POST")
@RequestMapping("/api/testOAuth/TestAccessToken")
public String TestAccessToken()
{
JWTUserDetails userDetails = (JWTUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String userid = userDetails.getUserId();
return "test oauth" + userid;
}
}
生成token接口:http://127.0.0.1:8080/api/testOAuth2/GetToken
授权访问接口:http://127.0.0.1:8080/api/testOAuth/TestAccessToken
文章来源: zzzili.blog.csdn.net,作者:清雨小竹,版权归原作者所有,如需转载,请联系作者。
原文链接:zzzili.blog.csdn.net/article/details/79398803
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)