当前位置:   article > 正文

SpringSecurity与JWT整合_jjwt spring-jwt

jjwt spring-jwt

SpringSecurity与JWT整合

数据库基于:SpringSecurity从数据库中获取用户信息进行验证

依赖:

<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.4</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.21</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

application.properties:

spring.thymeleaf.cache=false
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springsecurity001?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
mybatis.mapper-locations=classpath:mapper/*.xml
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

启动类SecurityJwtApplication:

@SpringBootApplication
@MapperScan("com.blu.mapper")
public class SecurityJwtApplication {

	public static void main(String[] args) {
		SpringApplication.run(SecurityJwtApplication.class, args);
	}
	
	@Bean
	public BCryptPasswordEncoder bcryptPasswordEncoder(){
		return new BCryptPasswordEncoder();
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

MyUser:

@Data
public class MyUser implements UserDetails {
	
	private Integer id;
	private String name;
	private String password;
	private List<MyRole> roles;

	@JsonIgnore
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return roles;
	}

	@JsonIgnore
	@Override
	public String getUsername() {
		return name;
	}

	@JsonIgnore
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@JsonIgnore
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@JsonIgnore
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@JsonIgnore
	@Override
	public boolean isEnabled() {
		return true;
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

MyRole:

@Data
public class MyRole implements GrantedAuthority {
	
	private Integer id;
	private String name;

	@JsonIgnore
	@Override
	public String getAuthority() {
		return name;
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

MyUserMapper:

public interface MyUserMapper {
	MyUser findByName(String name);
}
  • 1
  • 2
  • 3
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.blu.mapper.MyUserMapper">
	<resultMap type="com.blu.entity.MyUser" id="myUserMap">
		<id column="uid" property="id"></id>
		<result column="uname" property="name"></result>
		<result column="password" property="password"></result>
		<collection property="roles" ofType="com.blu.entity.MyRole">
			<id column="rid" property="id" />
			<result column="rname" property="name" />
		</collection>
	</resultMap>

	<select id="findByName" parameterType="String"
		resultMap="myUserMap">
		select u.id uid,u.name uname,u.password,r.id rid,r.name rname
		from user u,role r,role_user ur 
		where u.name = #{name} and ur.user_id = u.id and ur.role_id = r.id
	</select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

UserService:

public interface UserService extends UserDetailsService {

}
  • 1
  • 2
  • 3

UserServiceImpl:

@Service
public class UserServiceImpl implements UserService {
	
	@Autowired
	private MyUserMapper myUserMapper;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		MyUser myUser = myUserMapper.findByName(username);
		return myUser;
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

JwtLoginFilter:

public class JwtLoginFilter extends AbstractAuthenticationProcessingFilter {
	
	public JwtLoginFilter(String defaultFilterProcessesUrl, AuthenticationManager authenticationManager) {

		super(new AntPathRequestMatcher(defaultFilterProcessesUrl));
		setAuthenticationManager(authenticationManager);
	}


	/**
	 * 从登录参数json数据中获取用户名密码,然后调用AuthenticationManager.authenticate()方法进行校验。
	 */
	@Override
	public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse resp) throws AuthenticationException, IOException, ServletException {
		//将用户传的json数据转为user对象
		MyUser user = new ObjectMapper().readValue(req.getInputStream(),MyUser.class);
		return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword()));
	}

	/**
	 * 校验成功
	 */
	@Override
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
		Collection<? extends GrantedAuthority> authorities = authResult.getAuthorities();
		StringBuffer sb = new StringBuffer();
		for (GrantedAuthority authority : authorities) {
			sb.append(authority.getAuthority()).append(",");
		}
		String jwt = Jwts.builder()
				.claim("authorities", sb)
				.setSubject(authResult.getName())
				.setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 1000))//设置过期时间
				.signWith(SignatureAlgorithm.HS512, "root@123")//设置加密方式,以及key
				.compact();
		//设置登录成功后返回的信息
		Map<String,String> map = new HashMap<>();
		map.put("token",jwt);
		map.put("msg","登录成功");
		response.setContentType("application/json;charset=utf-8");
		PrintWriter writer = response.getWriter();
		writer.write(new ObjectMapper().writeValueAsString(map));
		writer.flush();
		writer.close();
	}

	/**
	 * 校验失败
	 */
	@Override
	protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
		Map<String,String> map = new HashMap<>();
		map.put("msg","登录失败");
		response.setContentType("application/json;charset=utf-8");
		PrintWriter writer = response.getWriter();
		writer.write(new ObjectMapper().writeValueAsString(map));
		writer.flush();
		writer.close();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

JwtFilter:

public class JwtFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
       HttpServletRequest req =  (HttpServletRequest) servletRequest;
       //从请求头中获取token
        String jwtToken = req.getHeader("authorization");
        Jws<Claims> jws = Jwts.parser().setSigningKey("root@123")
                .parseClaimsJws(jwtToken.replace("Bearer", ""));
        Claims claims = jws.getBody();
        String username = claims.getSubject();
        //获取角色
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList((String) claims.get("authorities"));
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username,"",authorities);
        SecurityContextHolder.getContext().setAuthentication(token);
        filterChain.doFilter(servletRequest,servletResponse);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

测试接口:

@RestController
public class StringController {
	
	@GetMapping("hello")
	public String hello() {
		return "hello BLU!";
	}
	
	@GetMapping("hi")
	public String hi() {
		return "hi everyone!";
	}
	
	@GetMapping("admin")
	public String admin() {
		return "hello admin!";
	}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

Security配置类:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
	
	@Autowired
	private UserServiceImpl userServiceImpl;
	@Autowired
	private BCryptPasswordEncoder bcryptPasswordEncoder;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		
		http.authorizeRequests()
			.antMatchers(HttpMethod.GET,"/hi").permitAll()
			.antMatchers("/hello").hasRole("vip1")
			.antMatchers("/admin").hasRole("admin");
		
		http.formLogin().loginPage("/tologin")
						.usernameParameter("name")
						.passwordParameter("password")
						.loginProcessingUrl("/login");
		
		http.csrf().disable();
		
		http.addFilterBefore(new JwtLoginFilter("/login",authenticationManager()),
                UsernamePasswordAuthenticationFilter.class)
        	.addFilterBefore(new JwtFilter(),UsernamePasswordAuthenticationFilter.class);
		
	}
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		
		auth.userDetailsService(userServiceImpl).passwordEncoder(bcryptPasswordEncoder);
	}
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

测试错误密码登录:
在这里插入图片描述
测试正确密码登录:
在这里插入图片描述
测试访问(有权限):
在这里插入图片描述
测试访问(无权限):
在这里插入图片描述
测试访问(错误token):
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/989861
推荐阅读
相关标签
  

闽ICP备14008679号