一、使用security默认登录接口登录成功、生成token、返回前段
项目的结构如下:
1.引入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- alibaba json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
<!--swagger相关-start-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.19</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--swagger相关-end-->
测试的用户实体
@Data
public class User {
private String id;
private String name;
private String password;
private boolean dev;
private boolean channel;
public User() {
}
public User(String id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
}
Jwt生成token,拦截和验证token的合法性
package com.example.security.Jwt;
import com.example.security.token.TokenManager;
import com.example.security.util.SpringContextUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
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.List;
import java.util.stream.Collectors;
/**
* Created by zhicheng.zhao on 2020/9/4.
*/
public class JwtAuthFilter extends BasicAuthenticationFilter {
private TokenManager tokenManager;
public JwtAuthFilter(AuthenticationManager authenticationManager, TokenManager tokenManager) {
super(authenticationManager);
this.tokenManager = tokenManager;
}
/**
* 过滤器
*
* @param request
* @param response
* @param chain
* @throws IOException
* @throws ServletException
*/
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
// 设置请求权限
response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,OPTIONS,DELETE,PATCH");
response.setHeader("Access-Control-Allow-Headers", "tokenId,userType,token,Origin,X-Requested-With,Content-Type,Accept,appKey,hszCookie");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json,charset=utf-8");
String url = request.getRequestURI();
// 鉴权判断:本地环境模拟管理员权限,其他环境需要根据url鉴权 zzc
System.out.println(SpringContextUtil.getProp("authVerify"));
if (SpringContextUtil.getProp("authVerify")==null?false:SpringContextUtil.getProp("authVerify").equalsIgnoreCase("false1")) {
// 本地环境,存储用户认证信息
String tokenTmp = tokenManager.createTokenAll("test");
UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(tokenTmp);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
chain.doFilter(request, response);
return;
} else if (urlFilter(url)) {
chain.doFilter(request, response);
return;
}
// 过滤token为空
String token = request.getHeader("token");
if (token == null || "".equals(token)) {
response.setHeader("Content-Type", "application/json");
response.getWriter().print("token为空!");
return;
}
// 从token获取用户认证信息
UsernamePasswordAuthenticationToken authenticationToken = getAuthentication(token);
if (authenticationToken == null) {
response.setHeader("Content-Type", "application/json");
response.getWriter().print("token信息错误!");
return;
}
// 存储用户认证信息
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
chain.doFilter(request, response);
}
/**
* 不需要token的地址:
* 用户名登录/手机登录/第三方登录/微信登录
* 注册
* 登录前(authFree)
*
* @param url
* @return
*/
private boolean urlFilter(String url) {
return url.contains("/login")
|| url.contains("Login")
|| url.contains("/regist")
|| url.contains("Regist")
|| url.contains("/authFree");
}
/**
* 从token获取用户认证信息
*
* @param token
* @return
*/
private UsernamePasswordAuthenticationToken getAuthentication(String token) {
try {
Claims claims = Jwts.parser()
.setSigningKey("JwtSecret")
.parseClaimsJws(token)
.getBody();
String user = claims.getSubject();
String role = claims.get("roles").toString();
List<SimpleGrantedAuthority> userRolesByToken = Arrays.stream(role.split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
if (!user.isEmpty()) {
return new UsernamePasswordAuthenticationToken(user, null, userRolesByToken);
}
} catch (Exception e) {
logger.info(e.getMessage());
}
return null;
}
}
查询数据库用户信息的服务
@Service
public class UserService {
/**
* @Description: 这里应该写的是调用Dao层,根据主键查询出用户,由于我没有配置直接返回用户,注意,密码是经过加密的
* @author: YunZhao.Wang
* @date: 2020/10/21 10:26
* @version:
*/
public User getUser(String name){
User user = new User("1","test", new BCryptPasswordEncoder().encode("123")) ;
if (user.getName().equals(name)){
return user;
}else {
return new User();
}
}
}
实现security底层查询用户信息的接口,让security的底层查询数据的用户信息
@Service
public class CustomUserService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
//账号信息
com.example.security.model.User accountInfo = userService.getUser(account);
if (accountInfo == null)
throw new UsernameNotFoundException("Account[" + account + "]not found");
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
//对应的权限添加
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(accountInfo.getName(), accountInfo.getPassword(), authorities);
}
}
集成 WebSecurityConfigurerAdapter,重写configure接口
package com.example.security.security;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.security.Jwt.JwtAuthFilter;
import com.example.security.model.User;
import com.example.security.token.TokenManager;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.builders.WebSecurity;
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.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @program: security进行登录
* @description: Security
* @author: YunZhao.Wang
* @create: 2020-10-21 10:29
**/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserService customUserService;
@Autowired
private TokenManager tokenManager;
@Override
public void configure(HttpSecurity http) throws Exception {
//关闭csrf保护
http.csrf().disable();
// 无状态
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// 添加filter
http.addFilterBefore(new JwtAuthFilter(authenticationManager(), tokenManager), UsernamePasswordAuthenticationFilter.class);
//登陆
http.formLogin().successHandler(loginSuccessHandler()).failureHandler(loginFailureHandler())
.permitAll();
// 无拦截
http.authorizeRequests().anyRequest().permitAll();
//退出
http.logout().logoutSuccessUrl("/login")
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService).passwordEncoder(passwordEncoder());
}
/**
* 密码加密
*
* @return
*/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
//密码加密
return new BCryptPasswordEncoder(4);
}
/**
* 登录成功
*
* @return
*/
@Bean
AuthenticationSuccessHandler loginSuccessHandler() {
return new AuthenticationSuccessHandler() {
@Autowired
private UserService userService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException {
String account = request.getParameter("username");
String token = tokenManager.createTokenBusiness(account);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json,charset=utf-8");
response.getWriter().print("登录成功!token:" + token);
}
};
}
/**
* 登录失败
*
* @return
*/
@Bean
AuthenticationFailureHandler loginFailureHandler() {
return new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// Result result = new Result(ExceptionEnum.LOGIN_ERROR.getErrorCode(), ExceptionEnum.LOGIN_ERROR.getErrorMsg());
// response.setHeader("Content-Type", "application/json");
response.getWriter().print("登录失败!");
}
};
}
/**
* 静态资源配置
*
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/swagger-ui.html")
.antMatchers("/webjars/**")
.antMatchers("/v2/**")
.antMatchers("/swagger-resources/**");
}
}
token工具类
package com.example.security.token;
import com.example.security.model.User;
import com.example.security.security.UserService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Created by zhangnianzhong on 2019/8/27.
*/
@Component("tokenManager")
public class TokenManager {
private static Logger logger = LoggerFactory.getLogger(TokenManager.class);
@Autowired
private UserService accountService;
public String createToken(String userId) {
long expire_time = 1000 * 60 * 60 * 12;
String token = Jwts.builder()
.setSubject(userId)
.setExpiration(new Date(System.currentTimeMillis() + expire_time))
.signWith(SignatureAlgorithm.HS512, "JwtSecret")
.compact();
return token;
}
/**
* B端用户权限
*
* @param userName
* @return
*/
public String createTokenBusiness(String userName) {
long expireTime = 1000 * 60 * 60 * 12; //过期时间为12小时
User account = accountService.getUser(userName);
List<String> list= new ArrayList<>();
//因为用户没有设置管理权限,故默认都是ROLE_00权限,在接口加注解包含00,即是管理员权限的接口
if (account.isDev()) {
list.add("ROLE_01");
}
if (account.isChannel()) {
list.add("ROLE_02");
}
if (!account.isChannel() && !account.isDev()) {
list.add("ROLE_00");
}
String token = Jwts.builder()
.signWith(SignatureAlgorithm.HS512, "JwtSecret")
.claim("roles", String.join(",", list))
.setSubject(userName)
.setExpiration(new Date(System.currentTimeMillis() + expireTime))
.compact();
return token;
}
/**
* 模拟所有用户权限
*
* @param userName
* @return
*/
public String createTokenAll(String userName) {
long expireTime = 1000 * 60 * 60 * 12;
List<String> list= new ArrayList<>();
list.add("ROLE_00");
list.add("ROLE_01");
list.add("ROLE_02");
list.add("ROLE_10");
list.add("ROLE_11");
String token = Jwts.builder()
.signWith(SignatureAlgorithm.HS512,"JwtSecret")
.claim("roles", String.join(",", list))
.setSubject(userName)
.setExpiration(new Date(System.currentTimeMillis() + expireTime))
.compact();
return token;
}
public String getRoles(String token) {
try {
Claims claims = Jwts.parser()
.setSigningKey("JwtSecret")
.parseClaimsJws(token)
.getBody();
String roles = claims.get("roles").toString();
return roles;
} catch (Exception e) {
logger.info(e.getMessage());
}
return null;
}
}
获取当前的环境
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext context = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.context = applicationContext;
}
// 传入线程中
public static <T> T getBean(String beanName) {
return (T) context.getBean(beanName);
}
// 国际化使用
public static String getMessage(String key) {
return context.getMessage(key, null, Locale.getDefault());
}
/// 获取当前环境
public static String getActiveProfile() {
return context.getEnvironment().getActiveProfiles()[0];
}
/// 获取当前环境
public static String getProp(String prop) {
return context.getEnvironment().getProperty(prop);
}
}
swagger配置文件
@Configuration
@EnableSwagger2
//@Profile({"test","dev","prod"})
public class Swagger2 {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.security.provider.controller"))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(setHeaderToken());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("权限版本二-V1-APIs")
.description("")
.termsOfServiceUrl("")
.version("1.0")
.build();
}
// 添加token验证
private List<Parameter> setHeaderToken() {
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
tokenPar.name("token").description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return pars;
}
}
controller接口
@RestController
@Api(tags = {"用户管理"},description = "带接口鉴权的用户管理接口")
public class UserController {
@PreAuthorize("hasAnyRole('00')")
@GetMapping("getUser")
@ApiOperation(value = "获取用户",notes = "获取用户")
public User getUser(){
return new User("3","ceshi","789");
}
}
配置文件
server.port= 10010
之后我们可以使用postman进行测试,使用security自带的login接口,是psot请求
二、请求头带上token访问后端接口
之后我们使用返回的token访问获取用户的接口,打开swagger接口(http://localhost:10010/swagger-ui.html),
因为默认都是00的权限,登录我是写死的,返回的一定也是00的权限,为了测试,我们修改获取用户借口中的注解参数
再次访问,出现403错误,无权限访问,现在的token是非00生成的,所以只能权限为非00的访问,这个返回结果我没有定义全局的异常处理,大家可以对异常进行再一次的封装
实例的连接
链接: https://pan.baidu.com/s/10ibBRxHEWakoENNBsvRALA 提取码: cd7u 复制这段内容后打开百度网盘手机App,操作更方便哦