1. 程式人生 > 其它 >雲e辦筆記(刪減)

雲e辦筆記(刪減)

1JwtTokenUtils工具

2公共返回物件

3Admin實現UserDetails

4AdminLoginParam

5AdminLoginController

6SecurityConfig

7RestAuthorizationEntryPoint

8RestfulAccessDeniedHandle

9ScurityConfig(增加Swagger2配置)

10Swagger2Config

1JwtTokenUtils工具

package com.xxxx.server.config.security;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtTokenUtils {
private static final String CLAIM_KEY_USERNAME="sub";
private static final String CLAIM_KEY_CREATED="created";
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;

/**
* 建立

token
* @param userDetails
* @return
*/
public String generateToken(UserDetails userDetails){
Map<String,Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME,userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED,new Date());
return generateToken(claims);
}
private String generateToken(Map<String,Object> claims){
return Jwts.builder()
.setClaims(claims)
.setExpiration(generateExpirationDate())
.signWith(SignatureAlgorithm.ES512,secret)
.compact();
}

private Date generateExpirationDate() {
return new Date(System.currentTimeMillis()+expiration*1000);
}

/**
* 解析
token,獲取使用者名稱
* @param token
* @return
*/
public String getUserNameToken(String token){
String username;
try {
Claims claims = getClaimsFormToken(token);
username = claims.getSubject();
}catch (Exception e){
e.printStackTrace();
username=null;
}

return username;

}

private Claims getClaimsFormToken(String token) {
Claims claims=null;
try{
claims=Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}catch (Exception e){
e.printStackTrace();
}
return claims;
}
/**
* 校驗是否真確

* @param token
* @param userDetails
* @return
*/
public boolean validateToken(String token,UserDetails userDetails){
String username = getUserNameToken(token);
return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
}
/**
* 是否可以重新整理時間
* @param token
* @return
*/
public boolean canRefresh(String token){
return !isTokenExpired(token);
}
/**
* 重新整理token
* @param token
* @return
*/
public String refreshToken(String token){
Claims claims = getClaimsFormToken(token);
claims.put(CLAIM_KEY_CREATED,new Date());
return generateToken(claims);
}
private boolean isTokenExpired(String token) {
Date expireDate=getExpiredDateFromToken(token);
return expireDate.before(new Date());
}
private Date getExpiredDateFromToken(String token) {
Claims claims =getClaimsFormToken(token);
return claims.getExpiration();
}
}

2公共返回物件

package com.xxxx.server.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RespBean {
private long code;
private String message;
private Object obj;
public static RespBean success(String message){
return new RespBean(200,message,null);
}

public static RespBean success(String message,Object obj){
return new RespBean(200,message,obj);
}

public static RespBean error(String message){
return new RespBean(500,message,null);
}
public static RespBean error(String message,Object obj){
return new RespBean(500,message,obj);
}
}

3Admin實現UserDetails

package com.xxxx.server.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Collection;

/**
* <p>
*
* </p>
*
* @author zhoubin
* @since 2021-09-09
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_admin")
@ApiModel(value="Admin物件", description="")
public class Admin implements Serializable, UserDetails {

private static final long serialVersionUID = 1L;

@ApiModelProperty(value = "id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;

@ApiModelProperty(value = "姓名")
private String name;

@ApiModelProperty(value = "手機號碼")
private String phone;

@ApiModelProperty(value = "住宅電話")
private String telephone;

@ApiModelProperty(value = "聯絡地址")
private String address;

@ApiModelProperty(value = "是否啟用")
private Boolean enabled;

@ApiModelProperty(value = "使用者名稱")
private String username;

@ApiModelProperty(value = "密碼")
private String password;

@ApiModelProperty(value = "使用者頭像")
private String userFace;

@ApiModelProperty(value = "備註")
private String remark;


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

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

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

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

@Override
public boolean isEnabled() {
return enabled;
}
}

4AdminLoginParam

package com.xxxx.server.pojo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value ="AdminLogin物件",description = "")
public class AdminLoginParam {
@ApiModelProperty(value ="使用者名稱",required =true)
private String username;
@ApiModelProperty(value ="密碼",required = true)
private String password;
}

5AdminLoginController

package com.xxxx.server.controller;

import com.xxxx.server.pojo.Admin;
import com.xxxx.server.pojo.AdminLoginParam;
import com.xxxx.server.pojo.RespBean;
import com.xxxx.server.service.IAdminService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.security.Principal;

@RestController
@Api(tags = "LoginController")
public class LoginController {
@Autowired
private IAdminService adminService;
@ApiOperation(value="登入之後返回token")
@PostMapping("/login")
public RespBean login(AdminLoginParam adminLoginParam, HttpServletRequest httpServletRequest){
return adminService.login(adminLoginParam.getUsername(),adminLoginParam.getPassword(),httpServletRequest);
}
@ApiOperation("獲取當前使用者資訊")
@PostMapping("/admin/info")
public Admin getAdminINfo(Principal principal){
if (null==principal){
return null;
}
String username = principal.getName();
Admin admin=adminService.getAdminByUserName(username);
admin.setPassword(null);
return admin;

}



@ApiOperation(value = "退出登入")
@RequestMapping("/logout")
public RespBean logout(){
return RespBean.success("登出成功!");
}
}

6SecurityConfig

package com.xxxx.server.config.security;

import com.xxxx.server.pojo.Admin;
import com.xxxx.server.service.IAdminService;
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private IAdminService adminService;
@Autowired
private RestAuthorizationEntryPoint restAuthorizationEntryPoint;
@Autowired
private ResstfulAccessDeniedHandler resstfulAccessDeniedHandler;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
//基於token,不要session
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)/*
ALWAYS
總是建立HttpSession IF_REQUIRED
Spring Security只會在需要時建立一個HttpSession
NEVER
Spring Security不會建立HttpSession,但如果它已經存在,將可以使用HttpSession
STATELESS
Spring Security永遠不會建立HttpSession,它不會使用HttpSession來獲取SecurityContext

*/
.and()
.authorizeRequests()
.antMatchers("/login","/logout")
.permitAll()
.anyRequest()
.authenticated()
.and()
.headers()
.cacheControl();
//新增登入授權攔截器
http.addFilterBefore(jwtAuthencationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//自定義未授權和未登入結果返回
http.exceptionHandling()
//訪問拒絕處理(許可權不足)
.accessDeniedHandler(resstfulAccessDeniedHandler)
//重新認證入口點(未登入)
.authenticationEntryPoint(restAuthorizationEntryPoint);
}

@Override
@Bean
public UserDetailsService userDetailsService(){
return username->{
Admin admin = adminService.getAdminByUserName(username);
if (null!=admin){
return admin;
}
return null;
};
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public JwtAuthencationTokenFilter jwtAuthencationTokenFilter(){
return new JwtAuthencationTokenFilter();
}
}

7RestAuthorizationEntryPoint

package com.xxxx.server.config.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xxxx.server.pojo.RespBean;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
* 未登入時返回的結果
*/
@Component
public class RestAuthorizationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json");
PrintWriter out =httpServletResponse.getWriter();
RespBean bean = RespBean.error("未登入");
bean.setCode(401);
out.write(new ObjectMapper().writeValueAsString(bean));
out.flush();
out.close();
}
}

8RestfulAccessDeniedHandle

package com.xxxx.server.config.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xxxx.server.pojo.RespBean;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
* 許可權不足返回的結果
*/
@Component
public class ResstfulAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json");
PrintWriter out = httpServletResponse.getWriter();
RespBean bean=RespBean.error("許可權不足");
bean.setCode(403);
out.write(new ObjectMapper().writeValueAsString(bean));
out.flush();
out.close();
}
}

9ScurityConfig(增加Swagger2配置)

package com.xxxx.server.config.security;

import com.xxxx.server.pojo.Admin;
import com.xxxx.server.service.IAdminService;
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.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private IAdminService adminService;
@Autowired
private RestAuthorizationEntryPoint restAuthorizationEntryPoint;
@Autowired
private ResstfulAccessDeniedHandler resstfulAccessDeniedHandler;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
//允許基於選擇匹配在資源級配置基於網路的安全性
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
//基於token,不要session
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)/*
ALWAYS
總是建立HttpSession IF_REQUIRED
Spring Security只會在需要時建立一個HttpSession
NEVER
Spring Security不會建立HttpSession,但如果它已經存在,將可以使用HttpSession
STATELESS
Spring Security永遠不會建立HttpSession,它不會使用HttpSession來獲取SecurityContext

*/
.and()
.authorizeRequests()
//websecurity已經配置
.antMatchers("/login","/logout")
.permitAll()
.anyRequest()
.authenticated()
.and()
.headers()
.cacheControl();
//新增登入授權攔截器
http.addFilterBefore(jwtAuthencationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
//自定義未授權和未登入結果返回
http.exceptionHandling()
//訪問拒絕處理(許可權不足)
.accessDeniedHandler(resstfulAccessDeniedHandler)
//重新認證入口點(未登入)
.authenticationEntryPoint(restAuthorizationEntryPoint);
}

//用於影響全域性安全性(配置資源,設定除錯模式,通過實現自定義防火牆定義拒絕請求)的配置設定。
//
//一般用於配置全域性的某些通用事物,例如靜態資源等
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/login","/logout","/css/**",
"/js/**","/index.html","favicon.ico","/doc.html",
"/webjars/**","/swagger-resources/**","/v2/api-docs/**");
}

/**
* 拉姆達表示式
* @return
*/
@Override
@Bean
public UserDetailsService userDetailsService(){

return username->{
Admin admin = adminService.getAdminByUserName(username);
if (null!=admin){
return admin;
}
return null;
};
}
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public JwtAuthencationTokenFilter jwtAuthencationTokenFilter(){
return new JwtAuthencationTokenFilter();
}
}

10Swagger2Config

package com.xxxx.server.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;


@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi(){
//文件型別SWAGGER_2
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.xxxx.server.controller"))
.paths(PathSelectors.any())
.build()
.securityContexts(securityContexts())
.securitySchemes(securitySchemes());
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("e")
.description("e辦介面文件")
//內容
.contact(new Contact("xxxx","http:8081/doc.html","[email protected]"))
.version("1.0")
.build();
}



private List<ApiKey> securitySchemes() {
List<ApiKey> result = new ArrayList<>();
ApiKey apiKey = new ApiKey("Authorization", "Authorization", "Header");
result.add(apiKey);
return result;
}

private List<SecurityContext> securityContexts(){
//設定需要登入認證的的路徑
List<SecurityContext> result = new ArrayList<>();
result.add(getContextByPath("/hello/.*"));
return result;
}

private SecurityContext getContextByPath(String pathRegex) {
return springfox.documentation.spi.service.contexts.SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex(pathRegex))
.build();
}

private List<SecurityReference> defaultAuth() {
List<SecurityReference> result = new ArrayList<>();
AuthorizationScope authorizationScope=new AuthorizationScope("global","accessEverything");
AuthorizationScope[] authorizationScopes=new AuthorizationScope[1];
authorizationScopes[0]=authorizationScope;
//下面要求要陣列才這樣
result.add(new SecurityReference("Authorization",authorizationScopes));
return result;

}

}