创新实训 11

创新实训 11,第1张

创新实训 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 authorityList = new ArrayList<>();
    /// =========================
    List editorRoleForUserVos = authorityService.selectRoleForUser(user.getUid());
    /// =========================

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

    return new EditorUserDetails(user, authorityList);
}

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

List editorRoleForUserVos = authorityService.selectRoleForUser(user.getUid());

调用了 authorityService 的 selectRoleForUser 方法

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

EditorAuthorityServiceImpl

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

@Override
@Transactional
public List selectRoleForUser(Integer userId) {
    List 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 getLatestNewId() {
    Long latestId = service.getLatestId() + 1;
    return CommonResult.success(latestId);
}
{
	"code": 200,
	"message": " *** 作成功",
	"data": 1
}

分析完毕

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5661438.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存