SpringBoot集成Spring security JWT实现接口权限认证

网友投稿 797 2023-01-29

SpringBoot集成Spring security JWT实现接口权限认证

SpringBoot集成Spring security JWT实现接口权限认证

1、添加依赖

org.springframework.boot

spring-boot-starter-security

io.jsonwebtoken

jjwt

0.9.1

2、集成JWT工具类(JwtUtils)

package com.dreamteam.chdapp.utils;

import io.jsonwebtoken.Jwts;

import io.jsonwebtoken.SignatureAlgorithm;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

/**

* @Author HeYunHui

* @create 2020/11/15 14:12

*/

public class JwtUtils {

private static final Logger logger= LoggerFactory.getLogger(JwtUtils.class);

public static final long EXPIRATION_TIME=60*60*1000;// 令牌环有效期

public static final String SECRET="abc123456def";//令牌环密钥

public static final String TOKEN_PREFIX="Bearer";//令牌环头标识

public static final String HEADER_STRING="Passport";//配置令牌环在http heads中的键值

public static final String ROLE="ROLE";//自定义字段-角色字段

//生成令牌环

public static String generateToken(String userRole,String userid){

HashMap map=new HashMap<>();

map.put(ROLE,userRole);

map.put("userid",userid);

String jwt= Jwts.builder()

.setClaims(map)

.setExpiration(new Date(System.currentTimeMillis()+EXPIRATION_TIME))

.signWith(SignatureAlgorithm.HS512,SECRET)

.compact();

return TOKEN_PREFIX+" "+jwt;

}

//生成令牌环

public static String generateToken(String userRole,String userid,long exprationtime){

HashMap map=new HashMap<>();

map.put(ROLE,userRole);

map.put("userid",userid);

String jwt= Jwts.builder()

.setClaims(map)

.setExpiration(new Date(System.currentTimeMillis()+exprationtime))

.signWith(SignatureAlgorithm.HS512,SECRET)

.compact();

return TOKEN_PREFIX+" "+jwt;

}

//令牌环校验

public static Map validateTokenAndGetClaims(HttpServletRequest request){

String token=request.getHeader(HEADER_STRING);

if(token==null){

throw new TokenValidationException("Missing Token");

}

else{

Map body= Jwts.parser()

.setSigningKey(SECRET)

.parseClaimsJws(token.replace(TOKEN_PREFIX,""))

.getBody();

return body;

}

}

static class TokenValidationException extends RuntimeException{

public TokenValidationException(String msg){

super(msg);

}

}

}

3、集成JWT filter(-/过滤器)

package com.dreamteam.chdapp.filter;

import com.dreamteam.chdapp.utils.JwtUtils;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;

import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.util.AntPathMatcher;

import org.springframework.util.PathMatcher;

import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.util.Arrays;

import java.util.Map;

import static com.dreamteam.chdapp.utils.JwtUtils.ROLE;

/**

* @Author HeYunHui

* @create 2020/11/15 14:46

*/

public class JwtAuthenticationFilter extends OncePerRequestFilter {

private static final PathMatcher pathmatcher = new AntPathMatcher();

private String[] protectUrlPattern = {"/manage/**", "/member/**", "/auth/**"}; //哪 些请求需要进行安全校验

public JwtAuthenticationFilter() {

}

@Override

protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

//是不是可以在这里做多种方式登录呢

try {

if (isProtectedUrl(httpServletRequest)) {

Map claims = JwtUtils.validateTokenAndGetClaims(httpServletRequest);

String role = String.valueOf(claims.get(ROLE));

String userid = String.valueOf(claims.get("userid"));

//最关键的部分就是这里, 我们直接注入了

SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(

userid, null, Arrays.asList(() -> role)

));

}

} catch (Exception e) {

e.printStackTrace();

httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());

return;

}

filterChain.doFilter(httpServletRequest, httpServletResponse);

}

//是否是保护连接

private boolean isProtectedUrl(HttpServletRequest request) {

boolean flag = false;

for (int i = 0; i < protectUrlPattern.length; i++) {

if (pathmatcher.match(protectUrlPattern[i], request.getServletPath())) {

return true;

}

}

return false;

}

}

4、配置JWT config类(配置类)

跨域访问:客户端与服务端域名不同或是端口号不同。防止跨域攻击

package edu.ynmd.cms.config;

import edu.ynmd.cms.filter.JwtAuthenticationFilter;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

import org.springframework.security.config.http.SessionCreationPolicy;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import org.springframework.security.crypto.password.PasswordEncoder;

import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import org.springframework.security.web.firewall.HttpFirewall;

import org.springframework.security.web.firewall.StrictHttpFirewall;

@Configuration

@EnableWebSecurity

@EnableGlobalMethodSecurity(prePostEnabled = true)

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Bean

public PasswordEncoder passwordEncoder(){

return new BCryptPasswordEncoder();

}

@Bean

public HttpFirewall allowUrlEncodedSlashHttpFirewall() {

StrictHttpFirewall firewall = new StrictHttpFirewall();

firewall.setAllowUrlEncodedSlash(true);

return firewall;

}

@Override

protected void configure(HttpSecurity http) throws Exception {

http.csrf().disable()

.cors() //允许跨域访问

.and()

.authorizeRequests()

.antMatchers("/").authenticated() //配置那些url需要进行校验--所有请求都需要校验"/"

.antMatchers("/public/**").permitAll() //那些请求不需要校验

.anyRequest().authenticated() //自定义校验类

.and()

.addFilterBefore(new JwtAuthenticationFilter(),

UsernamePasswordAuthenticationFilter.class)

.sessionManagement()

.sessionCreationPolicy(SessionCreationPolicy.STATELESS)//关闭session

;

}

}

5、Action注解

在Controller类中添加

@CrossOrigin

@RestController

@PreAuthorize("hasAuthority('admin')") //配置角色,拥有该角色的用户方可访问

@RequestMapping("/manage")

postman测试http://localhost:7070/manage/userList,不可访问

public开头的可以访问

6、token令牌环,访问需校验的资源

public的Controller类添加

@PostMapping("/login")

@ResponseBody

public HashMap login(

@RequestBody Account account) throws IOException {

// Users u=manageService.getUserByUserNameAndPass(account.username,account.password);

if(account.username.equals("admin")&&account.password.equals("123456")){

// if(u!=null){

String jwt= JwtUtils.generateToken("admin","123456789abc");

// String jwt= JwtUtils.generateToken(u.getRoleid(),u.getUsersid());

return new HashMap(){{

put("msg","ok");

put("token",jwt);

// put("role",u.getRoleid());

put("role","admin");

}};

}

else {

//return new ResponseEntity(HttpStatus.UNAUTHORIZED);

return new HashMap(){{

put("msg","error");

put("token","error");

}};

}

}

public static class Account{

public String username;

public String password;

}

postman测试,随便输用户名密码

输入代码中的用户名密码

去JWT官网https://jwt.io/,页面下滑,将得到的token输入,得到

manage的Controller类中添加测试

@GetMapping("testSecurityResource")

@ResponseBody

public String testSecurityResource() throws Exception{

return "受保护的资源";

}

用postman访问http://localhost:7070/manage/testSecurityResource,返回结果

7、service工具类

通用请求处理

package com.dreamteam.chdapp.controller.common;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Controller;

/**

* 通用请求处理

* @Author HeYunHui

* @create 2020/11/14 15:38

*/

@Controller

public class CommonController {

protected static final Logger log= LoggerFactory.getLogger(CommonController.class);

/**

* 字符串为空

* @param value

* @return

*/

public static boolean isNullOrSpace(String value){

if(value==null){

return true;

}

else {

if(value.equals("")){

return true;

}

else {

return false;

}

}

}

}

Service层

String getCurrentUserId();//从令牌环中获取userid

String getCurrentRole();//从令牌环中获取角色id

ServiceImpl

/**

* 获取当前登录用的的Id

* @return

*/

@Override

public String getCurrentUserId() {

String userid= (String) SecurityContextHolder.getContext().getAuthentication() .getPrincipal();

if(CommonController.isNullOrSpace(userid)){

return null;

}

else {

return userid;

}

}

/**

* 获取当前登录用户的角色

* @return

*/

@Override

public String getCurrentRole() {

String role=null;

Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities();

for (GrantedAuthority authority : authorities) {

role = authority.getAuthority();

}

if(CommonController.isNullOrSpace(role)){

return null;

}

else{

return role;

}

}

修改manage的Controller类

@GetMapping("testSecurityResource")

@ResponseBody

public String testSecurityResource() throws Exception{

String userid=userInfoService.getCurrentUserId();

String role=userInfoService.getCurrentRole();

return "受保护的资源,当前用户的id是"+userid+"当前用户的角色是"+role;

}

用postman测试

这是前面自定义的

8、识别token信息

如果将下图中的角色换掉,将不能访问

9、自动更新令牌环

添加Controller类

package com.dreamteam.chdapp.controller;

import com.dreamteam.chdapp.controller.common.CommonController;

import com.dreamteam.chdapp.utils.JwtUtils;

import org.springframework.security.access.prepost.PreAuthorize;

import org.springframework.security.core.GrantedAuthority;

import org.springframework.security.core.authority.SimpleGrantedAuthority;

import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

import java.util.Collection;

import java.util.HashMap;

/**

* 令牌环自动更新

* @Author HeYunHui

* @create 2020/11/16 17:24

* @PreAuthorize("hasAuthority('admin')")//只允许有admin角色的用户访问 hasAnyAuthority([auth1,auth2])

*/

@CrossOrigin

@RestController

@PreAuthorize("hasAnyAuthority('admin','member')")

@RequestMapping("/auth")

public class AuthController {

/**

* 更新令牌环信息

* @param request

* @return

*/

@GetMapping("refreshToken")

@ResponseBody

public HashMap refreshToken(HttpServletRequest request){

String role=null;

Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities();

for (GrantedAuthority authority : authorities) {

role = authority.getAuthority();

}

// UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication() .getPrincipal();

String userid= (String)SecurityContextHolder.getContext().getAuthentication() .getPrincipal();

if(CommonController.isNullOrSpace(role)){

return new HashMap(){{

put("token","error");

}};

}

else{

String jwt="";

//一小时

jwt= JwtUtils.generateToken(role,userid,60*60*1000);

HashMap m=new HashMap<>();

m.put("token",jwt);

return m;

}

}

/**

* 获取当前登录用户的角色

* @return

*/

@GetMapping("getRole")

@ResponseBody

public HashMap getRoleByToken(){

String role="";

String userid="";

Collection authorities = (Collection) SecurityContextHolder.getContext().getAuthentication().getAuthorities();

for (GrantedAuthority authority : authorities) {

role = authority.getAuthority();

}

if(CommonController.isNullOrSpace(role)){

return new HashMap(){{

put("role","error");

}};

}

else{

HashMap m=new HashMap<>();

m.put("role",role);

return m;

}

}

}

用postman测试

10、使用数据库存储用户信息

(1)实体类

package com.dreamteam.chdapp.entity;

import com.baomidou.mybatisplus.annotation.IdType;

import com.baomidou.mybatisplus.annotation.TableId;

import com.baomidou.mybatisplus.annotation.TableName;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

import org.springframework.stereotype.Component;

@Component

@Data

@AllArgsConstructor

@NoArgsConstructor

/**

* 表名

*/

@TableName("users")

public class Users {

@TableId(type = IdType.AUTO)

private String usrId;

private String usrName;

private String usrTel;

private String usrPwd;

private String usrType;

}

UserMapper

package com.dreamteam.chdapp.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import com.dreamteam.chdapp.entity.Users;

import org.apache.ibatis.annotations.Mapper;

import org.apache.ibatis.annotations.Param;

import org.springframework.stereotype.Repository;

import java.util.List;

/**

* @Author HeYunHui

* @create 2020/11/11 21:50

*/

@Repository

@Mapper

public interface UserMapper extends BaseMapper {

List getUsersByUsrNameAndPwd(@Param("usrName")String usrName, @Param("usrPwd") String usrPwd);

}

UsersMapper.xml

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

select * from users where #{usrName}=usr_name and #{usrPwd}=usr_pwd

service

Users getUsersByUsrNameAndPwd(String usrName,String usrPwd);

serviceImpl JWT获取用户名密码

@Override

public Users getUsersByUsrNameAndPwd(String usrName, String usrPwd) {

List ul=userMapper.getUsersByUsrNameAndPwd(usrName,usrPwd);

if(ul.size()>0){

return ul.get(0);

}

return null;

}

Controller

@PostMapping("/login")

@ResponseBody

public HashMap login(

@RequestBody Account account) throws IOException {

Users u=userInfoService.getUsersByUsrNameAndPwd(account.username,account.password);

// if(account.username.equals("admin")&&account.password.equals("123456")){

if(u!=null){

// String jwt= JwtUtils.generateToken("admin","123456789abc");

String jwt= JwtUtils.generateToken(u.getUsrType(),u.getUsrId());

return new HashMap(){{

put("msg","ok");

put("token",jwt);

put("role",u.getUsrType());

// put("role","admin");

}};

}

else {

//return new ResponseEntity(HttpStatus.UNAUTHORIZED);

return new HashMap(){{

put("msg","error");

put("token","error");

}};

}

}

public static class Account{

public String username;

public String password;

}

postman测试

a.登录,生成token

b.输入token访问manage下的链接

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:小程序 快应用(软件应用小程序)
下一篇:app跨端开发框架(跨平台移动应用开发框架)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~