龙空技术网

SpringSecurity和JWT实现认证和授权

架构师老狼 392

前言:

现在我们对“java培训认证”大致比较注意,各位老铁们都想要学习一些“java培训认证”的相关文章。那么小编也在网上搜集了一些关于“java培训认证””的相关资讯,希望大家能喜欢,大家快快来学习一下吧!

SpringSecurity

SpringSecurity是一个强大的可高度定制的认证和授权框架,对于Spring应用来说它是一套Web安全标准。SpringSecurity注重于为Java应用提供认证和授权功能,像所有的Spring项目一样,它对自定义需求具有强大的扩展性。

JWT

JWT是JSON WEB TOKEN的缩写,它是基于 RFC 7519

标准定义的一种可以安全传输的的JSON对象,由于使用了数字签名,所以是可信任和安全的。

JWT的组成WT token的格式:header.payload.signatureheader中用于存放签名的生成算法

{"alg": "HS512"}
payload中用于存放用户名、token的生成时间和过期时间
{"sub":"admin","created":1489079981393,"exp":1489684781}
signature为以header和payload生成的签名
String signature = HMACSHA512(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)
JWT实例
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImNyZWF0ZWQiOjE1NTY3NzkxMjUzMDksImV4cCI6MTU1NzM4MzkyNX0.d-iki0193X0bBOETf2UN3r3PotNIEAV7mzIxxeI5IxFyzzkOZxS0PGfF_SK6wxCv2K8S0cZjMkv6b5bCqc0VBw
JWT实现认证和授权的原理用户调用登录接口,登录成功后获取到JWT的token;之后用户每次调用接口都在http的header中添加一个叫Authorization的头,值为JWT的token;后台程序通过对Authorization头中信息的解码及数字签名校验来获取其中的用户信息,从而实现认证和授权。项目实战

1. 依赖引入

<!--SpringSecurity依赖配置--><dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-security</artifactId></dependency><!--JWT(Json Web Token)登录支持--><dependency>    <groupId>io.jsonwebtoken</groupId>    <artifactId>jjwt</artifactId>    <version>0.9.0</version></dependency>

2. JWT工具类

generateToken(UserDetails userDetails) :用于根据登录用户信息生成tokengetUserNameFromToken(String token):从token中获取登录用户的信息validateToken(String token, UserDetails userDetails):判断token是否还有效

    /**     * 根据负责生成JWT的token     */    private String generateToken(Map<String, Object> claims) {        return Jwts.builder()                .setClaims(claims)                .setExpiration(generateExpirationDate())                .signWith(SignatureAlgorithm.HS512, secret)                .compact();    }    /**     * 从token中获取登录用户名     */    public String getUserNameFromToken(String token) {        String username;        try {            Claims claims = getClaimsFromToken(token);            username =  claims.getSubject();        } catch (Exception e) {            username = null;        }        return username;    }    /**     * 验证token是否还有效     *     * @param token       客户端传入的token     * @param userDetails 从数据库中查询出来的用户信息     */    public boolean validateToken(String token, UserDetails userDetails) {        String username = getUserNameFromToken(token);        return username.equals(userDetails.getUsername()) && !isTokenExpired(token);    }

3. SpringSecurity配置

@Override    protected void configure(HttpSecurity httpSecurity) throws Exception {        httpSecurity.csrf()// 由于使用的是JWT,我们这里不需要csrf                .disable()                .sessionManagement()// 基于token,所以不需要session                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)                .and()                .authorizeRequests()                .antMatchers(HttpMethod.GET, // 允许对于网站静态资源的无授权访问                        "/", "/*.html", "/favicon.ico","/**/*.html",                        "/**/*.css","/**/*.js","/swagger-resources/**", "/v2/api-docs/**"                )                .permitAll()                .antMatchers("/admin/login", "/admin/register")// 对登录注册要允许匿名访问                .permitAll()                .antMatchers(HttpMethod.OPTIONS)//跨域请求会先进行一次options请求                .permitAll()               // .antMatchers("/**")//测试时全部运行访问              // .permitAll()                .anyRequest()// 除上面外的所有请求全部需要鉴权认证                .authenticated();        // 禁用缓存        httpSecurity.headers().cacheControl();        // 添加JWT filter        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);              //添加自定义未授权和未登录结果返回        httpSecurity.exceptionHandling()                .accessDeniedHandler(restfulAccessDeniedHandler)                .authenticationEntryPoint(restAuthenticationEntryPoint);    }

4.JwtAuthenticationTokenFilter

在用户名和密码校验前添加的过滤器,如果请求中有jwt的token且有效,会取出token中的用户名,然后调用SpringSecurity的API进行登录操作。

2021祝大家牛气冲天,事业家庭顺顺顺

@Override    protected void doFilterInternal(HttpServletRequest request,  HttpServletResponse response,                                    FilterChain chain) throws ServletException, IOException {        String authHeader = request.getHeader(this.tokenHeader);        if (authHeader != null && authHeader.startsWith(this.tokenHead)) {              // The part after "Bearer "            String authToken = authHeader.substring(this.tokenHead.length());            String username = jwtTokenUtil.getUserNameFromToken(authToken);            LOGGER.info("checking username:{}", username);                      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());                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));                    LOGGER.info("authenticated user:{}", username);                    SecurityContextHolder.getContext().setAuthentication(authentication);                }            }        }        chain.doFilter(request, response);    }

5. 备注说明

configure(HttpSecurity httpSecurity):用于配置需要拦截的url路径、jwt过滤器及出异常后的处理器;configure(AuthenticationManagerBuilder auth):用于配置UserDetailsService及PasswordEncoder;RestfulAccessDeniedHandler:当用户没有访问权限时的处理器,用于返回JSON格式的处理结果;RestAuthenticationEntryPoint:当未登录或token失效时,返回JSON格式的结果;UserDetailsService:SpringSecurity定义的核心接口,用于根据用户名获取用户信息,需要自行实现;UserDetails:SpringSecurity定义用于封装用户信息的类(主要是用户信息和权限),需要自行实现;PasswordEncoder:SpringSecurity定义的用于对密码进行编码及比对的接口,目前使用的是BCryptPasswordEncoder;JwtAuthenticationTokenFilter:在用户名和密码校验前添加的过滤器,如果有jwt的token,会自行根据token信息进行登录。

标签: #java培训认证