创新实训 11

2021SC@SDUSC

我们的项目中用到了很多关于Spring Security的内容,笔者虽然已经在学习Spring Security了,但是对于项目这种多个模块分离的Spring Security的使用流程还是不甚了解,今天我们就来理清一下项目中Spring Security 的逻辑。

JwtAuthenticationTokenFilter

首先我们看到位于security模块的 JwtAuthenticationTokenFilter 模块,他的 doFilterInternal 中关于当用户尚未认证时的处理逻辑为:

if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

    UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

    if (jwtTokenUtil.validateToken(authToken, userDetails)) {
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
 
        LOGGER.info("authenticated user: {}", username);
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}

这里可以看到他调用了 userDetailsService 的 loadUserByUsername 方法。但是笔者却发现 security 模块中并没有对应的 userDetailService 的实现类,于是笔者猜测,关于 userDetailService 的实现类应该是每一个需要 security 的模块自己实现的。

我们转到 doc 模块下。

EditorUserDetailsServiceImpl

可以看到这个模块中出现了对应的 UserDetailService 的实现类,我们观察他的 loadUserByUsername 方法的实现:

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    UmsUser user = userRepository.findByUsername(username).get(0);

    List<GrantedAuthority> authorityList = new ArrayList<>();
    /// =========================
    List<EditorRoleForUserVo> editorRoleForUserVos = authorityService.selectRoleForUser(user.getUid());
    /// =========================

    editorRoleForUserVos.forEach( role -> {
        authorityList.add(new SimpleGrantedAuthority(role.getRole_name()));
    });

    return new EditorUserDetails(user, authorityList);
}

可以看到,这个方法中的关键操作是

List<EditorRoleForUserVo> editorRoleForUserVos = authorityService.selectRoleForUser(user.getUid());

调用了 authorityService 的 selectRoleForUser 方法

我们需要找到 authorityService 的实现类。

EditorAuthorityServiceImpl

这个实现类中只实现了一个方法,也就是 selectRoleForUser :

@Override
@Transactional
public List<EditorRoleForUserVo> selectRoleForUser(Integer userId) {
    List<EditorRoleForUserVo> resultList = new ArrayList<>();
    StringBuilder sql_select_role_for_user = new StringBuilder();

    sql_select_role_for_user
        .append("select ")
        .append("u.uid uid, u.username username, r.rid rid, r.`name` role_name, r.description role_description ")
        .append("from ")
        .append("ums_user u ")
        .append("left join ums_user_role_relation ur on u.uid = ur.uid ")
        .append("left join ums_role r on ur.rid = r.rid ")
        .append("where ")
        .append("u.uid = ")
        .append(userId);

    Query query = entityManager.createNativeQuery(sql_select_role_for_user.toString());
    List list = query.unwrap(NativeQueryImpl.class)
        .setResultTransformer(Transformers.aliasToBean(EditorRoleForUserVo.class))
        .getResultList();

    list.forEach(item -> {
        resultList.add((EditorRoleForUserVo) item);
    });

    return resultList;
}

可以看到这里面有一个sql语句,我们首先观察一下他用到数据库,分别是

  • usm_user
  • ums_user_relation
  • ums_role

实际上这部操作可以得到user对应的role_name,并且返回一个list,表示这个user拥有的角色数。

查看了数据库后首先使用了正确的用户进行登录,获取到了token。

然后从JwtAuthenticationTokenFilter可得知,需要将这个token附到请求头中,并且需要将token前面加上一个特定的字符串。

进行了以上操作后,请求成功:

@PreAuthorize("hasAnyRole('administrator_editor', 'author', 'administrator')")
@RequestMapping(value = "/get_latest_id", method = RequestMethod.POST)
public CommonResult<Long> getLatestNewId() {
    Long latestId = service.getLatestId() + 1;
    return CommonResult.success(latestId);
}
{
	"code": 200,
	"message": "操作成功",
	"data": 1
}

分析完毕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值