一、参数格式
二、后端实现
Controller层
注意:LoginBody新增变量accessToken
@Service
public class ISingleTokenServiceImpl implements ISingleTokenService {
@Autowired
private TokenService tokenService;
@Autowired
private AuthenticationManager authenticationManager;
public String singleLogin(String accessToken) {
// 用户验证
Authentication authentication = null;
String username =accessToken;
try
{
// username=parseAccessToken(accessToken);
//不用进行处置 直接传参
authentication = authenticationManager
.authenticate(new IAuthenticationToken(username));
}
catch (Exception e)
{
if (e instanceof BadCredentialsException)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
else
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
throw new ServiceException(e.getMessage());
}
}
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
// 生成token
return tokenService.createToken(loginUser);
}
public String parseAccessToken(String accessToken) {
try {
// 从 access token 中提取 payload
Claims claims = Jwts.parser()
.parseClaimsJws(accessToken)
.getBody();
// 获取 username
String username = (String) claims.get("username");
return username;
} catch (Exception e) {
System.out.println("无法解析 access token!" + e);
return null;
}
}
- 添加自定义IAuthenticationToken
-
public class IAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
public IAuthenticationToken(Object principal) {
super(null);
this.principal = principal;
this.setAuthenticated(false);
}
public IAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException(
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
}
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
}
}添加IAuthenticationProvider
-
@Component
public class IAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
IAuthenticationToken authenticationToken = (IAuthenticationToken) authentication;
String username = (String) authenticationToken.getPrincipal();
UserDetails user = userDetailsService.loadUserByUsername(username);
IAuthenticationToken result = new IAuthenticationToken(user, Collections.emptyList());
/*
Details 中包含了 ip地址、 sessionId 等等属性 也可以存储一些自己想要放进去的内容
*/
result.setDetails(authenticationToken.getDetails());
return result;
}
@Override
public boolean supports(Class<?> aClass) {
return IAuthenticationToken.class.isAssignableFrom(aClass);
}
}修改SecurityConfig 放行我们的请求登录路径 并把自定义认证加进来
.antMatchers("/hello","/single/login","/login", "/register", "/captchaImage").anonymous()
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(new CustomLoginAuthenticationProvider(userDetailsService)); auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); auth.authenticationProvider(iAuthenticationProvider);
}
-
前端根据后台返回的token进行访问