LoginController类
具体代码
/**
* app 登录
*/
@AnonymousAccess
@PostMapping("login")
public AjaxResult login(@RequestBody LoginBody loginBody) {
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword());
ajax.put(Constants.TOKEN, token);
return ajax;
}
登录校验 ——AppLoginService类
具体代码
@Resource
private AppAuthenticationProvider authenticationManager;
/**
* 登录验证
*
* @param username 用户名
* @param password 密码
* @return 结果
*/
public String login(String username, String password) {
// 用户验证
Authentication authentication;
try {
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} 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();
recordLoginInfo(loginUser.getUserId());
// 生成token
return tokenService.createToken(loginUser);
}
AppAuthenticationProvider 类
具体代码
@Component
public class AppAuthenticationProvider implements AuthenticationProvider {
private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
@Autowired
private AppUserDetailsServiceImpl userDetailsService;
@SneakyThrows
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String userName = authentication.getName();// 这个获取表单输入中返回的用户名;
Object password = authentication.getCredentials();//这个获取表单输入中返回的密码;
// 这里构建来判断用户是否存在和密码是否正确
UserDetails userInfo = userDetailsService.loadUserByUsername(userName); // 这里调用我们的自己写的获取用户的方法;
if(!SecurityUtils.matchesPassword(password.toString(),userInfo.getPassword())){
log.info("用户不存在/密码错误,{}", userName);
throw new ServiceException("用户不存在/密码错误");
}
Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
// 构建返回的用户登录成功的token
return new UsernamePasswordAuthenticationToken(userInfo, userInfo.getPassword(), authorities);
}
@Override
public boolean supports(Class<?> authentication) {
// return authentication.equals(UsernamePasswordAuthenticationToken.class);
// 这里直接改成 return true;表示是支持这个执行
return true;
}
}
AppUserDetailsServiceImpl类
具体代码
@Service
public class AppUserDetailsServiceImpl implements UserDetailsService {
private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
@Autowired
private IProductMemberService memberService;//自己写的接口
@Autowired
private IProductMemberCourtService memberCourtService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
ProductMember member = memberService.selectUserByUserName(username);//验证登录用户
if (StringUtils.isNull(member)) {
log.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username + " 不存在");
} else if (UserStatus.DELETED.getCode().equals(member.getDelFlag())) {
log.info("登录用户:{} 已被删除.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
} else if (UserStatus.DISABLE.getCode().equals(member.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已停用");
}
return createLoginUser(member);
}
public UserDetails createLoginUser(ProductMember member) {
return new LoginUser(member.getMemberId(), memberCourtService.selectCourtIdByMemberId(member.getMemberId()), member);
}
}
此时运行时,会有冲突!!!
需要在 xxx-framework/src/main/java/....../SecurityConfig中条件
@Qualifier("userDetailsServiceImpl")
如图:
此时启动项目不会报冲突的错
千万千万要添加!!!
下图中的LongUser类要添加东西
要在public String getPassword(){}中添加自己写的登录实体类的getPassword()
以上内容已经可以解决app和小程序新的登录接口方案和后台管理的登陆获取token不冲突
以下内容可作为参考:
登录认证JWTtoken验证机制
后端部分
/login 接口
userName
password
code 验证码
前端获取上面三个要素后调用接口,整体改接口做了下面几件事情
1、验证用户身份(账号密码+验证码)
2、生成token
3、保存用户登录态到spring security中
安全配置:定义了基本的配置信息
framework.config.SecurityConfig
UserDetailsServiceImpl 用户验证处理类
登录接口的服务类
framework.web.service.SysLoginService
JWT拦截器,拦截令牌并校验信息
framework.security.filter.JwtAuthenticationTokenFilter
详细过程
1、SysLoginService 中调用UserDetailsServiceImpl校验用户的密码是否匹配以及用户账户状态,校验通过后返回UserDetails实例,该实例包含了用户的基本信息和菜单权限信息
2、调用tokenService.createToken(loginUser)生成token
令牌生成的详细过程
生成uuid随机数,这个随机数用来做rediskey存储token
生成一个token(无时效)
拦截到的token如果距离失效在10分钟以内(可配置)就自动刷新有效期
前面提到了token本身无时效,有效期是通过redis控制的,因为jwt本身未提供刷新有效期的方法(可能是我不知道)。
以上用户调用了login接口并且获得了token
jwt令牌校验
/**
* token过滤器 验证token有效性
*
* @author sj
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
{
@Autowired
private TokenService tokenService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException
{
LoginUser loginUser = tokenService.getLoginUser(request);
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
{
tokenService.verifyToken(loginUser);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
chain.doFilter(request, response);
}
}
代码比较短,所以就直接贴出来,这段代码拦截了所有请求并且完成了令牌的校验和刷新,具体过程如下
1、tokenService.getLoginUser(request); 从request中获取token并校验,如果校验通过就返回LoginUser对象
2、校验LoginUser的token,如果再刷限期内就直接刷新
3、将LoginUser封装到SecurityContextHolder中作为全局的用户登录状态
注:第3条有两个好处
1、后续拦截器发现SecurityContextHolder中保存了用户时,就直接通过校验
2、通过SecurityContextHolder可以快速获取当前请求的登录信息。
以上基本上已经说名了JWT校验的基本过程,忽略了很多细节
getInfo 获取用户信息
1、用户的基本信息
2、用户所有的Permissions(菜单树)
3、用户所有的RopePersmission(roleKeys)
getRouters 获取前端页面路由信息
这个接口完全为前端准备,后面会专门讲述前端的权限控制文章来源:https://www.toymoban.com/news/detail-729530.html
文章来源地址https://www.toymoban.com/news/detail-729530.html
到了这里,关于若依前后端分离版:增加新的登录接口,用于小程序或者APP获取token,并使用若依的验证方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!