Skip to content

Commit cf06116

Browse files
author
quding
committed
Spring Security Demo
1 parent 8207884 commit cf06116

File tree

12 files changed

+509
-1
lines changed

12 files changed

+509
-1
lines changed

README.MD

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,9 @@ SpringDataRedis学习的一个Demo,内容不多,配合博文:[redis学习记录(
6363
--------------
6464
增加Motan-Demo,一个基本的RPC调用Demo
6565

66-
15.待添加
66+
15.Spring-Security-Demo
67+
--------------
68+
增加Spring Security Demo,项目中使用了JWT Token验证机制,该项目可以很好的了解整个流程的作用,需要配合我博客中Spring Security相关博文食用.
69+
70+
16.待添加
6771
--------------

Spring-Security-Demo/pom.xml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>cn.mrdear.security</groupId>
8+
<artifactId>Spring-Security-Demo</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<parent>
12+
<groupId>org.springframework.boot</groupId>
13+
<artifactId>spring-boot-starter-parent</artifactId>
14+
<version>1.5.4.RELEASE</version>
15+
</parent>
16+
17+
<dependencies>
18+
<dependency>
19+
<groupId>org.springframework.boot</groupId>
20+
<artifactId>spring-boot-starter-security</artifactId>
21+
</dependency>
22+
<dependency>
23+
<groupId>org.springframework.boot</groupId>
24+
<artifactId>spring-boot-starter-web</artifactId>
25+
</dependency>
26+
<!--jwt依赖-->
27+
<dependency>
28+
<groupId>io.jsonwebtoken</groupId>
29+
<artifactId>jjwt</artifactId>
30+
<version>0.7.0</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.projectlombok</groupId>
34+
<artifactId>lombok</artifactId>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.apache.commons</groupId>
38+
<artifactId>commons-lang3</artifactId>
39+
<version>3.5</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>com.google.guava</groupId>
43+
<artifactId>guava</artifactId>
44+
<version>21.0</version>
45+
</dependency>
46+
</dependencies>
47+
48+
<build>
49+
<plugins>
50+
<plugin>
51+
<groupId>org.apache.maven.plugins</groupId>
52+
<artifactId>maven-compiler-plugin</artifactId>
53+
<configuration>
54+
<source>1.8</source>
55+
<target>1.8</target>
56+
</configuration>
57+
</plugin>
58+
</plugins>
59+
</build>
60+
61+
62+
</project>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package cn.mrdear.servuity;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
6+
/**
7+
* @author Niu Li
8+
* @since 2017/6/16
9+
*/
10+
@SpringBootApplication
11+
public class Application {
12+
13+
public static void main(String[] args) {
14+
SpringApplication.run(Application.class, args);
15+
}
16+
17+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package cn.mrdear.servuity.config;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
6+
import cn.mrdear.servuity.util.JwtTokenUtil;
7+
8+
/**
9+
* 配置一些线程安全的工具类
10+
* @author Niu Li
11+
* @since 2017/6/28
12+
*/
13+
@Configuration
14+
public class CommonBeanConfig {
15+
16+
/**
17+
* 配置jwt token
18+
*/
19+
@Bean
20+
public JwtTokenUtil configToken() {
21+
return new JwtTokenUtil();
22+
}
23+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package cn.mrdear.servuity.config;
2+
3+
import javax.servlet.FilterChain;
4+
import javax.servlet.FilterConfig;
5+
import javax.servlet.ServletException;
6+
import javax.servlet.ServletRequest;
7+
import javax.servlet.ServletResponse;
8+
import javax.servlet.http.HttpServletRequest;
9+
import javax.servlet.http.HttpServletResponse;
10+
11+
import java.io.IOException;
12+
13+
14+
public class CorsFilter implements javax.servlet.Filter {
15+
@Override
16+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
17+
System.err.println("CorsFilter");
18+
HttpServletResponse res = (HttpServletResponse) response;
19+
HttpServletRequest req = (HttpServletRequest) request;
20+
21+
res.setHeader("Access-Control-Allow-Origin", "*");
22+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, OPTIONS");
23+
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, Connection, User-Agent, authorization, sw-useragent, sw-version");
24+
25+
// Just REPLY OK if request method is OPTIONS for CORS (pre-flight)
26+
if (req.getMethod().equals("OPTIONS")) {
27+
res.setStatus(HttpServletResponse.SC_OK);
28+
return;
29+
}
30+
chain.doFilter(request, response);
31+
}
32+
33+
@Override
34+
public void destroy() {
35+
}
36+
37+
@Override
38+
public void init(FilterConfig filterConfig) throws ServletException {
39+
}
40+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package cn.mrdear.servuity.config;
2+
3+
import org.springframework.context.annotation.Configuration;
4+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
5+
import org.springframework.security.config.annotation.web.builders.WebSecurity;
6+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
7+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
8+
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
9+
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
10+
import org.springframework.security.web.context.NullSecurityContextRepository;
11+
12+
import cn.mrdear.servuity.util.JwtTokenUtil;
13+
14+
import javax.annotation.Resource;
15+
16+
/**
17+
* Spring Security配置类
18+
* @author Niu Li
19+
* @since 2017/6/16
20+
*/
21+
@Configuration
22+
@EnableWebSecurity
23+
public class SecurityConfig extends WebSecurityConfigurerAdapter {
24+
25+
@Resource
26+
private JwtTokenUtil jwtTokenUtil;
27+
28+
/**
29+
* 在此配置不过滤的请求
30+
*/
31+
@Override
32+
public void configure(WebSecurity web) throws Exception {
33+
//每一个请求对应一个空的filter链,这里一般不要配置过多,
34+
// 因为查找处是一个for循环,过多就导致每个请求都需要循环一遍直到找到
35+
web.ignoring().antMatchers("/","/login","/favicon.ico");
36+
}
37+
38+
/**
39+
* 在此配置过滤链
40+
*/
41+
@Override
42+
protected void configure(HttpSecurity http) throws Exception {
43+
http
44+
.authorizeRequests()
45+
//角色定义,Spring Security会在其前面自动加上ROLE_,因此存储权限的时候也要加上ROLE_ADMIN
46+
.antMatchers("/detail").access("hasRole('ADMIN')")
47+
.anyRequest().permitAll().and()
48+
//异常处理,可以再此使用entrypoint来定义错误输出
49+
.exceptionHandling().and()
50+
//不需要session来控制,所以这里可以去掉
51+
.securityContext().securityContextRepository(new NullSecurityContextRepository()).and()
52+
//开启匿名访问
53+
.anonymous().and()
54+
//退出登录自己来控制
55+
.logout().disable()
56+
//因为没用到cookies,所以关闭cookies
57+
.csrf().disable()
58+
//允许跨域
59+
.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class)
60+
//验证token
61+
.addFilterBefore(new VerifyTokenFilter(jwtTokenUtil),
62+
UsernamePasswordAuthenticationFilter.class);
63+
}
64+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package cn.mrdear.servuity.config;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
5+
import org.springframework.security.core.Authentication;
6+
import org.springframework.security.core.context.SecurityContextHolder;
7+
import org.springframework.web.filter.OncePerRequestFilter;
8+
9+
import cn.mrdear.servuity.util.JwtTokenUtil;
10+
import io.jsonwebtoken.JwtException;
11+
12+
import javax.servlet.FilterChain;
13+
import javax.servlet.ServletException;
14+
import javax.servlet.http.HttpServletRequest;
15+
import javax.servlet.http.HttpServletResponse;
16+
17+
import java.io.IOException;
18+
import java.util.Optional;
19+
20+
/**
21+
* jwt token验证类,验证成功后设置进去SecurityContext中
22+
* @author Niu Li
23+
* @since 2017/6/28
24+
*/
25+
@Slf4j
26+
public class VerifyTokenFilter extends OncePerRequestFilter {
27+
28+
private JwtTokenUtil jwtTokenUtil;
29+
30+
public VerifyTokenFilter(JwtTokenUtil jwtTokenUtil) {
31+
this.jwtTokenUtil = jwtTokenUtil;
32+
}
33+
34+
@Override
35+
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
36+
try {
37+
Optional<Authentication> authentication = jwtTokenUtil.verifyToken(request);
38+
log.debug("VerifyTokenFilter result: {}",authentication.orElse(null));
39+
SecurityContextHolder.getContext().setAuthentication(authentication.orElse(null));
40+
filterChain.doFilter(request,response);
41+
} catch (JwtException e) {
42+
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
43+
//可以在这里指定重定向还是返回错误接口示例
44+
}
45+
}
46+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package cn.mrdear.servuity.controller;
2+
3+
import com.google.common.collect.Lists;
4+
5+
import org.apache.commons.lang3.StringUtils;
6+
import org.springframework.security.core.Authentication;
7+
import org.springframework.security.core.context.SecurityContextHolder;
8+
import org.springframework.web.bind.annotation.GetMapping;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
import cn.mrdear.servuity.dto.TokenUserDTO;
12+
import cn.mrdear.servuity.util.JwtTokenUtil;
13+
14+
import javax.annotation.Resource;
15+
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
import java.util.Objects;
19+
20+
/**
21+
* @author Niu Li
22+
* @since 2017/6/19
23+
*/
24+
@RestController
25+
public class LoginCntroller {
26+
27+
@Resource
28+
private JwtTokenUtil jwtTokenUtil;
29+
30+
/**
31+
* 该链接获取token
32+
*/
33+
@GetMapping("/login")
34+
public Map login(String username, String password) {
35+
Map<String, Object> map = new HashMap<>();
36+
if (!StringUtils.equals(username, "demo") || !StringUtils.equals(password, "demo")) {
37+
map.put("status", 4);
38+
map.put("msg", "登录失败,用户名密码错误");
39+
return map;
40+
}
41+
TokenUserDTO userDTO = new TokenUserDTO();
42+
userDTO.setUsername(username);
43+
userDTO.setRoles(Lists.newArrayList("ROLE_ADMIN"));
44+
userDTO.setId(1L);
45+
userDTO.setEmail("1015315668@qq.com");
46+
userDTO.setAvatar("ahahhahahhaha");
47+
map.put("status", 1);
48+
map.put("msg", "Success");
49+
map.put("token", jwtTokenUtil.create(userDTO));
50+
return map;
51+
}
52+
53+
/**
54+
* 该链接尝试获取登录用户,返回该认证用户的信息,请求该链接需要在header中放入x-authorization: token
55+
*/
56+
@GetMapping("/detail")
57+
public TokenUserDTO userDetail() {
58+
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
59+
if (Objects.isNull(authentication)) {
60+
return null;
61+
}
62+
return (TokenUserDTO) authentication.getDetails();
63+
}
64+
65+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package cn.mrdear.servuity.dto;
2+
3+
import org.springframework.security.core.Authentication;
4+
import org.springframework.security.core.GrantedAuthority;
5+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
6+
7+
import java.util.Collection;
8+
import java.util.stream.Collectors;
9+
10+
/**
11+
* Spring Security中存放的认证用户
12+
* @author Niu Li
13+
* @since 2017/6/28
14+
*/
15+
public class TokenUserAuthentication implements Authentication {
16+
17+
private static final long serialVersionUID = 3730332217518791533L;
18+
19+
private TokenUserDTO userDTO;
20+
21+
private Boolean authentication = false;
22+
23+
public TokenUserAuthentication(TokenUserDTO userDTO, Boolean authentication) {
24+
this.userDTO = userDTO;
25+
this.authentication = authentication;
26+
}
27+
28+
@Override
29+
public Collection<? extends GrantedAuthority> getAuthorities() {
30+
return userDTO.getRoles().stream()
31+
.map(SimpleGrantedAuthority::new).collect(Collectors.toList());
32+
}
33+
34+
@Override
35+
public Object getCredentials() {
36+
return userDTO.getPassword();
37+
}
38+
39+
@Override
40+
public Object getDetails() {
41+
return userDTO;
42+
}
43+
44+
@Override
45+
public Object getPrincipal() {
46+
return userDTO.getUsername();
47+
}
48+
49+
@Override
50+
public boolean isAuthenticated() {
51+
return authentication;
52+
}
53+
54+
@Override
55+
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
56+
this.authentication = isAuthenticated;
57+
}
58+
59+
@Override
60+
public String getName() {
61+
return userDTO.getUsername();
62+
}
63+
}

0 commit comments

Comments
 (0)