请求
当请求一个/system/user/deptTree 部门树的接口请求
后台经历了哪些过程
首先
1.会经过一个过滤器,在JwtAuthenticationTokenFilter类中的doFilterInternal方法拿到request,通过request.getHeader("Authorization")方法拿到整个token。
2.使用Jwts.parser()...解析token中的数据,获得登录时存在JWT中的数据,这个数据是一个uuid,而这个uuid对应着登录时保存在redis中用户信息的key,通过这个key就拿到了这个用户的所有信息。然后去更新redis中这个key的过期时间,这个过期时间就是配置文件中令牌的有效期。
//解析token中的数据
private Claims parseToken(String token)
{
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
//Claims作用
User user = xxxx;//你的用户实体类
Map<String, Object> test = new HashMap<>();
test.put("id", user.getId());
test.put("name", user.getName());
String token = JWTUtil.createJWT(test);
return R.ok().put("token", token);
public R test(HttpServletRequest request) {
String token = request.getHeader(AuthConsts.AUTHORIZATION_HEADER);
Claims claims = JWTUtil.parseJWT(appConfig.getJwtSecret(), token);
System.out.println("这是id"+claims.get("id", Integer.class));
System.out.println("这是名称"+claims.get("name", String.class));
return R.data(claims);
}
输出>这是id 1
输出> 这是名称 DadiaoMan
3.设置UsernamePasswordAuthenticationToken authenticationToken的值,分别为:
principal为当前用户loginUser
credentials为null
authorities为loginUser.getAuthorities()
Details为当前访问主机的ip地址
设置安全上下文的Authentication,SecurityContextHolder.getContext().setAuthentication(authenticationToken)
过滤器的工作完成了
然后
4.如果当前的接口加了@PreAuthorize("@ss.hasPermi('system:dept:list')")注解,就会进入PermissionService这个Service,PermissionService中有一个 hasPermi(String permission)方法,里面通过LoginUser loginUser =SecurityUtils.getLoginUser();获取用户信息,用来查询当前用户是否有'system:dept:list'的权限字符。如果有这个权限信息,设置PermissionContextHolder(权限信息)的值为'system:dept:list'(可以这么理解,实际上是将这个值给了RequestContextHolder),然后进入这个接口内部执行具体方法。如果有这个权限信息,报403,"没有权限,请联系管理员授权"
//SecurityUtils类中的方法
public static LoginUser getLoginUser()
{
try
{
Object principal = getAuthentication().getPrincipal();
return (LoginUser) getAuthentication().getPrincipal();
}
catch (Exception e)
{
throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
}
}
public static Authentication getAuthentication()
{
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();//第3步中设置的值
return SecurityContextHolder.getContext().getAuthentication();
}
而在SecurityUtils类中获取的权限信息就是在第3步中设置的值,SecurityContextHolder.getContext().getAuthentication();
补充:RequestContextHolder的作用(SpringMVC之RequestContextHolder分析 - 水狼一族 - 博客园 (cnblogs.com))
正常来说在service层是没有request的,然而直接从controlller传过来的话解决方法太粗暴,后来发现了SpringMVC提供的RequestContextHolder,可以获取到request
最后
5.进入service层的方法,service加了@DataScope(deptAlias = "d")注解
在DataScopeAspect类中有拦截加了@DataScope注解的方法
@Before("@annotation(controllerDataScope)") //拦截加了@DataScope
public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
{
clearDataScope(point);
handleDataScope(point, controllerDataScope);
}
在DataScopeAspect里面获取部门信息,设置补充的sql。
设置${params.dataScope}
BaseEntity baseEntity = (BaseEntity) params;
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
parameterType="SysDept" SysDept继承了BaseEntity,所以${params.dataScope}会生效
public class SysDept extends BaseEntity
<select id="selectDeptList" parameterType="SysDept" resultMap="SysDeptResult">
<include refid="selectDeptVo"/>
where d.del_flag = '0'
<if test="deptId != null and deptId != 0">
AND dept_id = #{deptId}
</if>
<if test="parentId != null and parentId != 0">
AND parent_id = #{parentId}
</if>
<if test="deptName != null and deptName != ''">
AND dept_name like concat('%', #{deptName}, '%')
</if>
<if test="status != null and status != ''">
AND status = #{status}
</if>
<!-- 数据范围过滤 -->
${params.dataScope}
order by d.parent_id, d.order_num
</select>
只能在controller跳到service层@DataScope生效问题。。。
@Aspect如果被spring容器加载的话,而@Controller注解的这些类的实例化以及注入却是由SpringMVC来完成。 @Aspect如果被spring容器加载的时候,可能Spring MVC容器还未初始化, Controller类还未初始化,所以无法正常织入
想在service内部调用的话使用
SpringUtils.getAopProxy(this).selectDeptList(dept);
登录
首先通过/captchaImage接口获取验证码
然后调用/login接口来验证
在/login这个接口中调用SysLoginService的方法
1.验证码校验,验证码信息是存在redis中的验证码信息
2.前置校验,校验用户名和密码是否符合格式、ip黑名单等等
3.将用户信息存进UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
AuthenticationContextHolder.setContext(authenticationToken);
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
authentication = authenticationManager.authenticate(authenticationToken);