文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringSecurity整合jwt权限认证的全流程讲解

2024-04-02 19:55

关注

JWT

本文代码截取自实际项目。

jwt(Json Web Token),一个token,令牌。

简单流程:

用户登录成功后,后端返回一个token,也就是颁发给用户一个凭证。之后每一次访问,前端都需要携带这个token,后端通过token来解析出当前访问对象。

优点

1、一定程度上解放了后端,后端不需要再记录当前用户是谁,不需要再维护一个session,节省了开销。

2、session依赖于cookie,某些场合cookie是用不了的,比如用户浏览器cookie被禁用、移动端无法存储cookie等。

缺点

1、既然服务器通过token就可以知道当前用户是谁,说明其中包含了用户信息,有一定的泄露风险。

2、因为是无状态的,服务器不维持会话,那么每一次请求都会重新去数据库读取权限信息,性能有一定影响。

(如果想提高性能,可以将权限数据存到redis,但是如果用redis,就已经失去了jwt的优点,直接用普通的token+redis即可)

3、只能校验token是否正确,通过设定过期时间来确定其有效性,不可以手动注销。

先说怎么做,再说为什么。

代码

依赖


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <security.version>2.3.3.RELEASE</security.version>
        </dependency>
 
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <jwt.version>0.9.1</jwt.version>
        </dependency>

jwt工具类


public class JwtTokenUtils implements Serializable { 
    private static final long serialVersionUID = -3369436201465044824L; 
    //生成token
    public static String createToken(String username) {
        return Jwts.builder().setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis()+ Constants.Jwt.EXPIRATION))
                .signWith(SignatureAlgorithm.HS512, Constants.Jwt.KEY).compressWith(CompressionCodecs.GZIP).compact();
    }
 
    //获取用户名
    public static String getUserName(String token) {
        return Jwts.parser().setSigningKey(Constants.Jwt.KEY).parseClaimsJws(token).getBody().getSubject();
    }
}

涉及常量


public interface Constants {
    public interface Jwt{
        
        String KEY = "123123";
        
        long EXPIRATION = 7200000;
        
        String TOKEN_HEAD = "Authorization";
    }
}

实体类和Service

为了减少对实体类的入侵,我又定义了一个对象

原实体类



@Data
@TableName("tb_user_info")
public class UserInfo implements Serializable {
	private static final long serialVersionUID = 1L;
 
	
	@TableId(type = IdType.AUTO)
	private Integer id;
	
	private String loginName;
	
	private String dispName;
	
	private String password;
	
	private Byte status;
	
	@TableField(fill = FieldFill.INSERT)
	private Integer createBy;
	
	@TableField(fill = FieldFill.INSERT_UPDATE)
	private Integer updateBy;
	
	@TableField(fill = FieldFill.INSERT)
	private Date createTime;
	
	@TableField(fill = FieldFill.INSERT_UPDATE)
	private Date updateTime;
	
	@TableLogic
	private Byte deleted;
}

定义对象


@Data
public class UserSecurity implements UserDetails {
    private static final long serialVersionUID = -6777760550924505136L;
    private UserInfo userInfo;
    private List<String> permissionValues;
    public UserSecurity(UserInfo userInfo) {
        this.userInfo = userInfo;
    }
 
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        for(String permissionValue : permissionValues) {
            if(StringUtils.isEmpty(permissionValue)) continue;
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
            authorities.add(authority);
        }
 
        return authorities;
    }
 
    @Override
    public String getPassword() {
        return userInfo.getPassword();
    }
 
    @Override
    public String getUsername() {
        return userInfo.getLoginName();
    }
 
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
 
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
 
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
 
    @Override
    public boolean isEnabled() {
        return true;
    }
}

service


@Service
public class UserInfoServiceImpl implements  UserInfoService, UserDetailsService {
 
    @Autowired
    UserInfoMapper userInfoMapper;
 
    @Autowired
    PermissionService permissionService;
 
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("login_name", username);
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        List<String> rights = permissionService.listPermissions(username);
        UserSecurity userSecurity = new UserSecurity(userInfo);
        userSecurity.setPermissionValues(rights);
        return userSecurity;
    }
}

配置类


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    UserInfoServiceImpl userInfoService;
 
    @Autowired
    JwtAuthorizationTokenFilter jwtAuthorizationTokenFilter;
 
    @Autowired
    TokenLoginFilter tokenLoginFilter;
 
    @Autowired
    JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
 
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userInfoService).passwordEncoder(passwordEncoderBean());
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling()
                .authenticationEntryPoint(jwtAuthenticationEntryPoint)
                .and().csrf().disable()
                .authorizeRequests()
                .antMatchers("/login").permitAll()
                .antMatchers("/hello").permitAll()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/webjars
    public UserInfo getCurrentUser() {
        return (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    }
}

这里的UserInfo对象,就是principal。

如果你上面放的不对象,而是用户名或者id,那么获取principal的时候,自然是对应的用户名或者id了。

种瓜得瓜,种豆得豆。

配置文件

截取核心片段加点注释。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯