前言
登录权限问题在需求中很常见的,比如qq有很多会员,每个会员的有很多不同的权限,
步骤一
基本配置
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<!-- redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.10.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.0</version>
</dependency>
2.重写这个类 解决SpringDataJpa实体类中属性顺序与数据库中生成字段顺序不一致的问题
/**
* 解决SpringDataJpa实体类中属性顺序与数据库中生成字段顺序不一致的问题 */
class PropertyContainer {
private static final CoreMessageLogger LOG = (CoreMessageLogger)Logger.getMessageLogger(CoreMessageLogger.class, PropertyContainer.class.getName());
private final XClass xClass;
private final XClass entityAtStake;
private final AccessType classLevelAccessType;
private final LinkedHashMap<String, XProperty> persistentAttributeMap;
PropertyContainer(XClass clazz, XClass entityAtStake, AccessType defaultClassLevelAccessType) {
this.xClass = clazz;
this.entityAtStake = entityAtStake;
if (defaultClassLevelAccessType == AccessType.DEFAULT) {
defaultClassLevelAccessType = AccessType.PROPERTY;
}
AccessType localClassLevelAccessType = this.determineLocalClassDefinedAccessStrategy();
assert localClassLevelAccessType != null;
this.classLevelAccessType = localClassLevelAccessType != AccessType.DEFAULT ? localClassLevelAccessType : defaultClassLevelAccessType;
assert this.classLevelAccessType == AccessType.FIELD || this.classLevelAccessType == AccessType.PROPERTY;
this.persistentAttributeMap = new LinkedHashMap<>();
List<XProperty> fields = this.xClass.getDeclaredProperties(AccessType.FIELD.getType());
List<XProperty> getters = this.xClass.getDeclaredProperties(AccessType.PROPERTY.getType());
this.preFilter(fields, getters);
Map<String, XProperty> persistentAttributesFromGetters = new HashMap();
this.collectPersistentAttributesUsingLocalAccessType(this.persistentAttributeMap, persistentAttributesFromGetters, fields, getters);
this.collectPersistentAttributesUsingClassLevelAccessType(this.persistentAttributeMap, persistentAttributesFromGetters, fields, getters);
}
private void preFilter(List<XProperty> fields, List<XProperty> getters) {
Iterator propertyIterator = fields.iterator();
XProperty property;
while(propertyIterator.hasNext()) {
property = (XProperty)propertyIterator.next();
if (mustBeSkipped(property)) {
propertyIterator.remove();
}
}
propertyIterator = getters.iterator();
while(propertyIterator.hasNext()) {
property = (XProperty)propertyIterator.next();
if (mustBeSkipped(property)) {
propertyIterator.remove();
}
}
}
private void collectPersistentAttributesUsingLocalAccessType(LinkedHashMap<String, XProperty> persistentAttributeMap, Map<String, XProperty> persistentAttributesFromGetters, List<XProperty> fields, List<XProperty> getters) {
Iterator propertyIterator = fields.iterator();
XProperty xProperty;
Access localAccessAnnotation;
while(propertyIterator.hasNext()) {
xProperty = (XProperty)propertyIterator.next();
localAccessAnnotation = (Access)xProperty.getAnnotation(Access.class);
if (localAccessAnnotation != null && localAccessAnnotation.value() == javax.persistence.AccessType.FIELD) {
propertyIterator.remove();
persistentAttributeMap.put(xProperty.getName(), xProperty);
}
}
propertyIterator = getters.iterator();
while(propertyIterator.hasNext()) {
xProperty = (XProperty)propertyIterator.next();
localAccessAnnotation = (Access)xProperty.getAnnotation(Access.class);
if (localAccessAnnotation != null && localAccessAnnotation.value() == javax.persistence.AccessType.PROPERTY) {
propertyIterator.remove();
String name = xProperty.getName();
XProperty previous = (XProperty)persistentAttributesFromGetters.get(name);
if (previous != null) {
throw new MappingException(LOG.ambiguousPropertyMethods(this.xClass.getName(), HCANNHelper.annotatedElementSignature(previous), HCANNHelper.annotatedElementSignature(xProperty)), new Origin(SourceType.ANNOTATION, this.xClass.getName()));
}
persistentAttributeMap.put(name, xProperty);
persistentAttributesFromGetters.put(name, xProperty);
}
}
}
private void collectPersistentAttributesUsingClassLevelAccessType(LinkedHashMap<String, XProperty> persistentAttributeMap, Map<String, XProperty> persistentAttributesFromGetters, List<XProperty> fields, List<XProperty> getters) {
Iterator var5;
XProperty getter;
if (this.classLevelAccessType == AccessType.FIELD) {
var5 = fields.iterator();
while(var5.hasNext()) {
getter = (XProperty)var5.next();
if (!persistentAttributeMap.containsKey(getter.getName())) {
persistentAttributeMap.put(getter.getName(), getter);
}
}
} else {
var5 = getters.iterator();
while(var5.hasNext()) {
getter = (XProperty)var5.next();
String name = getter.getName();
XProperty previous = (XProperty)persistentAttributesFromGetters.get(name);
if (previous != null) {
throw new MappingException(LOG.ambiguousPropertyMethods(this.xClass.getName(), HCANNHelper.annotatedElementSignature(previous), HCANNHelper.annotatedElementSignature(getter)), new Origin(SourceType.ANNOTATION, this.xClass.getName()));
}
if (!persistentAttributeMap.containsKey(name)) {
persistentAttributeMap.put(getter.getName(), getter);
persistentAttributesFromGetters.put(name, getter);
}
}
}
}
public XClass getEntityAtStake() {
return this.entityAtStake;
}
public XClass getDeclaringClass() {
return this.xClass;
}
public AccessType getClassLevelAccessType() {
return this.classLevelAccessType;
}
public Collection<XProperty> getProperties() {
this.assertTypesAreResolvable();
return Collections.unmodifiableCollection(this.persistentAttributeMap.values());
}
private void assertTypesAreResolvable() {
Iterator var1 = this.persistentAttributeMap.values().iterator();
XProperty xProperty;
do {
if (!var1.hasNext()) {
return;
}
xProperty = (XProperty)var1.next();
} while(xProperty.isTypeResolved() || discoverTypeWithoutReflection(xProperty));
String msg = "Property " + StringHelper.qualify(this.xClass.getName(), xProperty.getName()) + " has an unbound type and no explicit target entity. Resolve this Generic usage issue or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type";
throw new AnnotationException(msg);
}
private AccessType determineLocalClassDefinedAccessStrategy() {
AccessType hibernateDefinedAccessType = AccessType.DEFAULT;
AccessType jpaDefinedAccessType = AccessType.DEFAULT;
org.hibernate.annotations.AccessType accessType = (org.hibernate.annotations.AccessType)this.xClass.getAnnotation(org.hibernate.annotations.AccessType.class);
if (accessType != null) {
hibernateDefinedAccessType = AccessType.getAccessStrategy(accessType.value());
}
Access access = (Access)this.xClass.getAnnotation(Access.class);
if (access != null) {
jpaDefinedAccessType = AccessType.getAccessStrategy(access.value());
}
if (hibernateDefinedAccessType != AccessType.DEFAULT && jpaDefinedAccessType != AccessType.DEFAULT && hibernateDefinedAccessType != jpaDefinedAccessType) {
throw new org.hibernate.MappingException("@AccessType and @Access specified with contradicting values. Use of @Access only is recommended. ");
} else {
AccessType classDefinedAccessType;
if (hibernateDefinedAccessType != AccessType.DEFAULT) {
classDefinedAccessType = hibernateDefinedAccessType;
} else {
classDefinedAccessType = jpaDefinedAccessType;
}
return classDefinedAccessType;
}
}
private static boolean discoverTypeWithoutReflection(XProperty p) {
if (p.isAnnotationPresent(OneToOne.class) && !((OneToOne)p.getAnnotation(OneToOne.class)).targetEntity().equals(Void.TYPE)) {
return true;
} else if (p.isAnnotationPresent(OneToMany.class) && !((OneToMany)p.getAnnotation(OneToMany.class)).targetEntity().equals(Void.TYPE)) {
return true;
} else if (p.isAnnotationPresent(ManyToOne.class) && !((ManyToOne)p.getAnnotation(ManyToOne.class)).targetEntity().equals(Void.TYPE)) {
return true;
} else if (p.isAnnotationPresent(ManyToMany.class) && !((ManyToMany)p.getAnnotation(ManyToMany.class)).targetEntity().equals(Void.TYPE)) {
return true;
} else if (p.isAnnotationPresent(Any.class)) {
return true;
} else if (p.isAnnotationPresent(ManyToAny.class)) {
if (!p.isCollection() && !p.isArray()) {
throw new AnnotationException("@ManyToAny used on a non collection non array property: " + p.getName());
} else {
return true;
}
} else if (p.isAnnotationPresent(Type.class)) {
return true;
} else {
return p.isAnnotationPresent(Target.class);
}
}
private static boolean mustBeSkipped(XProperty property) {
return property.isAnnotationPresent(Transient.class) || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals(property.getType().getName()) || "org.hibernate.bytecode.internal.javassist.FieldHandler".equals(property.getType().getName());
}
}
3.application.yml配置数据库和jpa
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql:///你的数据库
username: root
password: *****
jpa:
database: mysql
show-sql: true
hibernate:
ddl-auto: update
naming:
physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
步骤二
配置security的配置类
设置权限分配
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(-1)
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(10);
}
/**
* 不使用数据库
* @param http
* @throws Exception
*/
// @Override
// protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication()
// .withUser("admin").password("$2a$10$U3EkVjomZM2YJ/E3weONZO2H4Zm7K0hB6hgPiqhUv73vxXx92M/ne").roles("ADMIN","USER")
// .and()
// .withUser("sang").password("$2a$10$QcJ7zeDeqJQh/ZNt08x4xuvHy4utVMvmbzcsKNvtF.SxAXOgq.k2C").roles("USER");
// }
/**
* 使用数据库
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
/*
当已经认证过的用户尝试再次认证时,应用针对该事件有几种处理方式。
可以注销当前用户session,使用新的session重新认证,或允许两个session并存。
*/
// @Bean
// public HttpSessionEventPublisher httpSessionEventPublisher() {
// return new HttpSessionEventPublisher();
// }
@Override
protected void configure(HttpSecurity http) throws Exception {
//先配置session
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests()
.antMatchers("/admin/**")
.hasRole("admin")
.antMatchers("/db/**")
.access("hasRole('admin') and hasRole('dba')")
.anyRequest()
//必须认证访问
// .authenticated()
.permitAll()
.and()
.formLogin()
.loginPage("/login_page")
.loginProcessingUrl("/login")
.usernameParameter("user")
.passwordParameter("passwd")
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication auth) throws IOException, ServletException {
Object principal =auth.getPrincipal();
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
HashMap<String, Object> map = new HashMap<>();
map.put("status",200);
map.put("msg", principal);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
HashMap<String, Object> map = new HashMap<>();
map.put("msg","没有权限");
map.put("status",400);
ObjectMapper om = new ObjectMapper();
out.write(om.writeValueAsString(map));
out.flush();
out.close();
}
})
.and()
//对于没有配置权限的其他请求允许匿名访问
.anonymous()
.and()
.logout()
.logoutUrl("logout")
//get请求
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
.clearAuthentication(true)
.invalidateHttpSession(true)
.addLogoutHandler(new LogoutHandler() {
@Override
public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
}
})
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
PrintWriter writer = resp.getWriter();
req.setCharacterEncoding("utf-8"); // 设置request字符编码
String searchText = req.getParameter("search"); // 获取传入的search字段的内容
resp.setContentType("text/json; charset=utf-8"); // 设置response的编码及格式
PrintWriter out = resp.getWriter();
Map<String,Object> resMap = new HashMap<>();
//200成功 400代表失败
resMap.put("code",200);
String resJSON = JSON.toJSONString(resMap); // 转换为json
out.print(resJSON);
}
})
.permitAll()
.and()
.cors()//新加入
.and()
.csrf()
.disable();
}
}
步骤三
首先创建实体类
User和Role
user
@Data
@Entity(name = "user")
public class User implements UserDetails , Serializable {
private static final long serialVersionUID = -5470916854745278810L;
@Id
@Column(name = "id", columnDefinition = "varchar(255)")
private String id;
@Column(name = "username", columnDefinition = "varchar(255)")
private String username;
@Column(name = "password", columnDefinition = "varchar(255)")
private String password;
@Column(name = "enabled", columnDefinition = "boolean")
private boolean enabled =true;
@Column(name = "locked", columnDefinition = "boolean")
private boolean locked =false;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
private List<Role> roles;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : getRoles()) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return !locked;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
public User() {
}
public User(String id, String username, String password, boolean enabled, boolean locked, List<GrantedAuthority> roles) {
this.id=id;
this.username=username;
this.password=password;
this.enabled=enabled;
this.locked=locked;
List<Role> roleList=new ArrayList<>();
roles.forEach(it->{
Role role = new Role();
role.setId(10L);
role.setName(it.toString());
role.setNameZh("测试权限");
roleList.add(role);
});
this.roles=roleList;
}
}
Role
@Data
@Entity(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String nameZh;
}
编写roleDao和userDao
public interface UserDao extends JpaRepository<User, Long> {
User findUserByUsername(String username);
User findUserById(String id);
}
public interface RoleDao extends JpaRepository<Role, Long> {
Role findRoleByName(String name);
}
实现UserDetailsService方法重写loadUserByUsername
@Service
public class UserService implements UserDetailsService {
@Autowired
UserDao userDao;
// UserDetails
/**
* 根据用户名加载用户信息
*
* @param username 用户名
* @return UserDetails
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findUserByUsername(username);
//动态添加用户到数据库,然后登录
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
return user;
}
}
login和logout已经定义好了
最后实现注册的代码
/**
* 注册一个用户
* @return
*/
@PostMapping("/register")
public Map<String,Object> register(String user,String passwd){
// System.out.println(user);
// System.out.println(passwd);
// 默认添加admin的权限
//添加默认的属性
//然后
User new_user =new User();
//
//
//
new_user.setUsername(user);
new_user.setId(uuidUtil.getUUID());
String encode_pass = passwordEncoder.encode(passwd);
new_user.setPassword(encode_pass);
Role role_admin = roleDao.findRoleByName("ROLE_user");
//
//
//
//
List<Role> list =new ArrayList<>();
//
list.add(role_admin);
list.add(role);
//
new_user.setRoles(list);
//
userDao.save(new_user);
//
Map<String, Object> result = new HashMap<>();
result.put("res",200);
return result;
}
这就整合完毕了,欢迎观看
点个赞再走呗~