Sprint Boot使用OAuth和JWT实现身份认证【一】
【摘要】
依赖第三方库:
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)